1 /*
2 * Copyright (c) 2021 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 #include <mutex>
16 #include <openssl/sha.h>
17 #include <string>
18 #include <sys/time.h>
19 #include <thread>
20 #include <variant>
21 #include <vector>
22
23 #include "cloud/cloud_db_constant.h"
24 #include "concurrent_adapter.h"
25 #include "db_common.h"
26 #include "db_constant.h"
27 #include "kv_store_errno.h"
28 #include "param_check_utils.h"
29 #include "platform_specific.h"
30 #include "relational_store_client.h"
31 #include "runtime_context.h"
32 #include "sqlite_utils.h"
33
34 // using the "sqlite3sym.h" in OHOS
35 #ifndef USE_SQLITE_SYMBOLS
36 #include "sqlite3.h"
37 #else
38 #include "sqlite3sym.h"
39 #endif
40
41 #if defined _WIN32
42 #ifndef RUNNING_ON_WIN
43 #define RUNNING_ON_WIN
44 #endif
45 #else
46 #ifndef RUNNING_ON_LINUX
47 #define RUNNING_ON_LINUX
48 #endif
49 #endif
50
51 #if defined(RUNNING_ON_LINUX)
52 #include <unistd.h>
53 #elif defined RUNNING_ON_WIN
54 #include <io.h>
55 #else
56 #error "PLATFORM NOT SPECIFIED!"
57 #endif
58
59 #ifdef DB_DEBUG_ENV
60 #include "system_time.h"
61
62 using namespace DistributedDB::OS;
63 #endif
64 using namespace DistributedDB;
65
66 namespace {
67 constexpr int E_OK = 0;
68 constexpr int E_ERROR = 1;
69 constexpr int STR_TO_LL_BY_DEVALUE = 10;
70 constexpr int BUSY_TIMEOUT = 2000; // 2s.
71 constexpr int MAX_BLOB_READ_SIZE = 5 * 1024 * 1024; // 5M limit
72 const std::string DEVICE_TYPE = "device";
73 const std::string SYNC_TABLE_TYPE = "sync_table_type_";
74 class ValueHashCalc {
75 public:
ValueHashCalc()76 ValueHashCalc() {};
~ValueHashCalc()77 ~ValueHashCalc()
78 {
79 delete context_;
80 context_ = nullptr;
81 }
82
Initialize()83 int Initialize()
84 {
85 context_ = new (std::nothrow) SHA256_CTX;
86 if (context_ == nullptr) {
87 return -E_ERROR;
88 }
89
90 int errCode = SHA256_Init(context_);
91 if (errCode == 0) {
92 return -E_ERROR;
93 }
94 return E_OK;
95 }
96
Update(const std::vector<uint8_t> & value)97 int Update(const std::vector<uint8_t> &value)
98 {
99 if (context_ == nullptr) {
100 return -E_ERROR;
101 }
102 int errCode = SHA256_Update(context_, value.data(), value.size());
103 if (errCode == 0) {
104 return -E_ERROR;
105 }
106 return E_OK;
107 }
108
GetResult(std::vector<uint8_t> & value)109 int GetResult(std::vector<uint8_t> &value)
110 {
111 if (context_ == nullptr) {
112 return -E_ERROR;
113 }
114
115 value.resize(SHA256_DIGEST_LENGTH);
116 int errCode = SHA256_Final(value.data(), context_);
117 if (errCode == 0) {
118 return -E_ERROR;
119 }
120
121 return E_OK;
122 }
123
124 private:
125 SHA256_CTX *context_ = nullptr;
126 };
127
128 using Timestamp = uint64_t;
129 using TimeOffset = int64_t;
130
131 class TimeHelper {
132 public:
133 // 10000 year 100ns
134 static constexpr int64_t BASE_OFFSET = 10000LL * 365LL * 24LL * 3600LL * 1000LL * 1000LL * 10L;
135
136 static constexpr int64_t MAX_VALID_TIME = BASE_OFFSET * 2; // 20000 year 100ns
137
138 static constexpr uint64_t TO_100_NS = 10; // 1us to 100ns
139
140 static constexpr Timestamp INVALID_TIMESTAMP = 0;
141
142 static constexpr uint64_t MULTIPLES_BETWEEN_SECONDS_AND_MICROSECONDS = 1000000;
143
144 static constexpr int64_t MAX_NOISE = 9 * 100 * 1000; // 900ms
145
146 static constexpr uint64_t MAX_INC_COUNT = 9; // last bit from 0-9
147
GetSysCurrentRawTime(uint64_t & curTime)148 static int GetSysCurrentRawTime(uint64_t &curTime)
149 {
150 static uint64_t lastCurTime = 0u;
151 int errCode = GetCurrentSysTimeInMicrosecond(curTime);
152 if (errCode != E_OK) {
153 return errCode;
154 }
155 curTime *= TO_100_NS;
156
157 std::lock_guard<std::mutex> lock(systemTimeLock_);
158 int64_t timeDiff = static_cast<int64_t>(curTime) - static_cast<int64_t>(lastCurTime);
159 if (std::abs(timeDiff) > 1000u) { // 1000 is us
160 lastCurTime = curTime;
161 return E_OK;
162 }
163 if (curTime <= lastCurTime) {
164 curTime = lastCurTime + 1;
165 }
166 lastCurTime = curTime;
167 return E_OK;
168 }
169
170 // Init the TimeHelper for time skew
Initialize()171 void Initialize()
172 {
173 // it maybe a rebuild db when initialize with localTimeOffset is TimeHelper::BASE_OFFSET
174 // reinitialize for this db
175 if (isInitialized_) {
176 return;
177 }
178 (void)GetCurrentSysTimeInMicrosecond(lastSystemTime_);
179 (void)OS::GetMonotonicRelativeTimeInMicrosecond(lastMonotonicTime_);
180 LOGD("Initialize time helper skew: %" PRIu64 " %" PRIu64, lastSystemTime_, lastMonotonicTime_);
181 isInitialized_ = true;
182 }
183
GetTime(TimeOffset timeOffset,const std::function<Timestamp ()> & getDbMaxTimestamp,const std::function<Timestamp ()> & getDbLocalTimeOffset)184 Timestamp GetTime(TimeOffset timeOffset, const std::function<Timestamp()> &getDbMaxTimestamp,
185 const std::function<Timestamp()> &getDbLocalTimeOffset)
186 {
187 if (!isLoaded_) { // First use, load max time stamp and local time offset from db;
188 if (getDbMaxTimestamp != nullptr) {
189 lastLocalTime_ = getDbMaxTimestamp();
190 }
191 if (getDbLocalTimeOffset != nullptr) {
192 localTimeOffset_ = getDbLocalTimeOffset();
193 }
194 LOGD("Use time helper with maxTimestamp:%" PRIu64 " localTimeOffset:%" PRIu64 " first time", lastLocalTime_,
195 localTimeOffset_);
196 isLoaded_ = true;
197 }
198 Timestamp currentSystemTime = 0u;
199 (void)GetCurrentSysTimeInMicrosecond(currentSystemTime);
200 Timestamp currentMonotonicTime = 0u;
201 (void)OS::GetMonotonicRelativeTimeInMicrosecond(currentMonotonicTime);
202 auto deltaTime = static_cast<int64_t>(currentMonotonicTime - lastMonotonicTime_);
203 Timestamp currentSysTime = GetSysCurrentTime();
204 Timestamp currentLocalTime = currentSysTime + timeOffset + localTimeOffset_;
205 if (currentLocalTime <= lastLocalTime_ || currentLocalTime > MAX_VALID_TIME) {
206 LOGD("Ext invalid time: lastLocalTime_: %" PRIu64 ", currentLocalTime: %" PRIu64 ", deltaTime: %" PRId64,
207 lastLocalTime_, currentLocalTime, deltaTime);
208 lastLocalTime_ = static_cast<Timestamp>(static_cast<int64_t>(lastLocalTime_) +
209 deltaTime * static_cast<int64_t>(TO_100_NS));
210 currentLocalTime = lastLocalTime_;
211 } else {
212 lastLocalTime_ = currentLocalTime;
213 }
214
215 lastSystemTime_ = currentSystemTime;
216 lastMonotonicTime_ = currentMonotonicTime;
217 return currentLocalTime;
218 }
219
TimeSkew(const std::function<Timestamp ()> & getLocalTimeOffsetFromDB,Timestamp timeOffset)220 bool TimeSkew(const std::function<Timestamp()> &getLocalTimeOffsetFromDB, Timestamp timeOffset)
221 {
222 Timestamp currentSystemTime = 0u;
223 (void)GetCurrentSysTimeInMicrosecond(currentSystemTime);
224 Timestamp currentMonotonicTime = 0u;
225 (void)OS::GetMonotonicRelativeTimeInMicrosecond(currentMonotonicTime);
226
227 auto systemTimeOffset = static_cast<int64_t>(currentSystemTime - lastSystemTime_);
228 auto monotonicTimeOffset = static_cast<int64_t>(currentMonotonicTime - lastMonotonicTime_);
229 if (std::abs(systemTimeOffset - monotonicTimeOffset) > MAX_NOISE) {
230 // time skew detected
231 Timestamp localTimeOffset = getLocalTimeOffsetFromDB();
232 Timestamp currentSysTime = GetSysCurrentTime();
233 Timestamp currentLocalTime = currentSysTime + timeOffset + localTimeOffset;
234 auto virtualTimeOffset = static_cast<int64_t>(currentLocalTime - lastLocalTime_);
235 auto changedOffset = static_cast<int64_t>(virtualTimeOffset - monotonicTimeOffset * TO_100_NS);
236 if (std::abs(changedOffset) > static_cast<int64_t>(MAX_NOISE * TO_100_NS)) { // LCOV_EXCL_BR_LINE
237 // localTimeOffset was not flushed, use temporary calculated value
238 localTimeOffset_ = static_cast<Timestamp>(static_cast<int64_t>(localTimeOffset_) -
239 (systemTimeOffset - monotonicTimeOffset) * static_cast<int64_t>(TO_100_NS));
240 LOGD("Save ext local time offset: %" PRIu64 ", changedOffset: %" PRId64, localTimeOffset_,
241 changedOffset);
242 } else {
243 localTimeOffset_ = localTimeOffset;
244 LOGD("Save ext local time offset: %" PRIu64, localTimeOffset_);
245 }
246 }
247 lastSystemTime_ = currentSystemTime;
248 lastMonotonicTime_ = currentMonotonicTime;
249 return std::abs(systemTimeOffset - monotonicTimeOffset) > MAX_NOISE;
250 }
251
GetLastTime() const252 Timestamp GetLastTime() const
253 {
254 return lastLocalTime_;
255 }
256
257 // Get current system time
GetSysCurrentTime()258 static Timestamp GetSysCurrentTime()
259 {
260 uint64_t curTime = 0;
261 int errCode = GetCurrentSysTimeInMicrosecond(curTime);
262 if (errCode != E_OK) {
263 return INVALID_TIMESTAMP;
264 }
265
266 std::lock_guard<std::mutex> lock(systemTimeLock_);
267 // If GetSysCurrentTime in 1us, we need increase the currentIncCount_
268 if (curTime == lastSystemTimeUs_) {
269 // if the currentIncCount_ has been increased MAX_INC_COUNT, keep the currentIncCount_
270 if (currentIncCount_ < MAX_INC_COUNT) { // LCOV_EXCL_BR_LINE
271 currentIncCount_++;
272 }
273 } else {
274 lastSystemTimeUs_ = curTime;
275 currentIncCount_ = 0;
276 }
277 return (curTime * TO_100_NS) + currentIncCount_; // Currently Timestamp is uint64_t
278 }
279
280 #ifndef DB_DEBUG_ENV
GetCurrentSysTimeInMicrosecond(uint64_t & outTime)281 static int GetCurrentSysTimeInMicrosecond(uint64_t &outTime)
282 {
283 struct timeval rawTime;
284 int errCode = gettimeofday(&rawTime, nullptr);
285 if (errCode < 0) {
286 return -E_ERROR;
287 }
288 outTime = static_cast<uint64_t>(rawTime.tv_sec) * MULTIPLES_BETWEEN_SECONDS_AND_MICROSECONDS +
289 static_cast<uint64_t>(rawTime.tv_usec);
290 return E_OK;
291 }
292 #endif
293
294 static std::mutex systemTimeLock_;
295 static Timestamp lastSystemTimeUs_;
296 static Timestamp currentIncCount_;
297
298 Timestamp lastLocalTime_ = 0;
299 Timestamp localTimeOffset_ = TimeHelper::BASE_OFFSET;
300 bool isLoaded_ = false;
301
302 Timestamp lastSystemTime_ = 0;
303 Timestamp lastMonotonicTime_ = 0;
304 bool isInitialized_ = false;
305 };
306
307 class TimeHelperManager {
308 public:
GetInstance()309 static TimeHelperManager *GetInstance()
310 {
311 static auto instance = new TimeHelperManager();
312 return instance;
313 }
314
AddStore(const std::string & storeId)315 void AddStore(const std::string &storeId)
316 {
317 std::lock_guard<std::mutex> lock(metaDataLock_);
318 if (metaData_.find(storeId) != metaData_.end()) {
319 return;
320 }
321 TimeHelper timeHelper;
322 timeHelper.Initialize();
323 metaData_[storeId] = timeHelper;
324 }
325
Restore(const std::string & storeId)326 void Restore(const std::string &storeId)
327 {
328 std::lock_guard<std::mutex> lock(metaDataLock_);
329 if (metaData_.find(storeId) != metaData_.end()) {
330 LOGD("Restore time helper");
331 metaData_.erase(storeId);
332 }
333 }
334
GetLastTime(const std::string & storeId)335 Timestamp GetLastTime(const std::string &storeId)
336 {
337 std::lock_guard<std::mutex> lock(metaDataLock_);
338 auto it = metaData_.find(storeId);
339 if (it == metaData_.end()) {
340 return TimeHelper::INVALID_TIMESTAMP;
341 }
342 return it->second.GetLastTime();
343 }
344
TimeSkew(const std::string & storeId,const std::function<Timestamp ()> & getLocalTimeOffsetFromDB,Timestamp timeOffset)345 bool TimeSkew(const std::string &storeId, const std::function<Timestamp()> &getLocalTimeOffsetFromDB,
346 Timestamp timeOffset)
347 {
348 std::lock_guard<std::mutex> lock(metaDataLock_);
349 auto it = metaData_.find(storeId);
350 if (it == metaData_.end()) {
351 return false;
352 }
353 return it->second.TimeSkew(getLocalTimeOffsetFromDB, timeOffset);
354 }
355
GetTime(const std::string & storeId,TimeOffset timeOffset,const std::function<Timestamp ()> & getDbMaxTimestamp,const std::function<Timestamp ()> & getDbLocalTimeOffset)356 Timestamp GetTime(const std::string &storeId, TimeOffset timeOffset,
357 const std::function<Timestamp()> &getDbMaxTimestamp, const std::function<Timestamp()> &getDbLocalTimeOffset)
358 {
359 std::lock_guard<std::mutex> lock(metaDataLock_);
360 auto it = metaData_.find(storeId);
361 if (it == metaData_.end()) {
362 return TimeHelper::INVALID_TIMESTAMP;
363 }
364 return it->second.GetTime(timeOffset, getDbMaxTimestamp, getDbLocalTimeOffset);
365 }
366 private:
367 TimeHelperManager() = default;
368 std::mutex metaDataLock_;
369 std::map<std::string, TimeHelper> metaData_;
370 };
371
372 std::mutex TimeHelper::systemTimeLock_;
373 Timestamp TimeHelper::lastSystemTimeUs_ = 0;
374 Timestamp TimeHelper::currentIncCount_ = 0;
375
376 int GetStatement(sqlite3 *db, const std::string &sql, sqlite3_stmt *&stmt);
377 int ResetStatement(sqlite3_stmt *&stmt);
378 int BindBlobToStatement(sqlite3_stmt *stmt, int index, const std::vector<uint8_t> &value, bool permEmpty = false);
379 int StepWithRetry(sqlite3_stmt *stmt);
380 int GetColumnBlobValue(sqlite3_stmt *stmt, int index, std::vector<uint8_t> &value);
381 int GetColumnTextValue(sqlite3_stmt *stmt, int index, std::string &value);
382 int GetDBIdentity(sqlite3 *db, std::string &identity);
383
384 struct TransactFunc {
385 void (*xFunc)(sqlite3_context*, int, sqlite3_value**) = nullptr;
386 void (*xStep)(sqlite3_context*, int, sqlite3_value**) = nullptr;
387 void (*xFinal)(sqlite3_context*) = nullptr;
388 void(*xDestroy)(void*) = nullptr;
389 };
390
391 std::mutex g_clientObserverMutex;
392 std::map<std::string, ClientObserver> g_clientObserverMap;
393 std::mutex g_clientChangedDataMutex;
394 std::map<std::string, ClientChangedData> g_clientChangedDataMap;
395
396 std::mutex g_storeObserverMutex;
397 std::map<std::string, std::list<std::shared_ptr<StoreObserver>>> g_storeObserverMap;
398 std::mutex g_storeChangedDataMutex;
399 std::map<std::string, std::vector<ChangedData>> g_storeChangedDataMap;
400
401 std::mutex g_clientCreateTableMutex;
402 std::set<std::string> g_clientCreateTable;
403
RegisterFunction(sqlite3 * db,const std::string & funcName,int nArg,void * uData,TransactFunc & func)404 int RegisterFunction(sqlite3 *db, const std::string &funcName, int nArg, void *uData, TransactFunc &func)
405 {
406 if (db == nullptr) {
407 return -E_ERROR;
408 }
409 return sqlite3_create_function_v2(db, funcName.c_str(), nArg, SQLITE_UTF8 | SQLITE_DETERMINISTIC, uData,
410 func.xFunc, func.xStep, func.xFinal, func.xDestroy);
411 }
412
CalcValueHash(const std::vector<uint8_t> & value,std::vector<uint8_t> & hashValue)413 int CalcValueHash(const std::vector<uint8_t> &value, std::vector<uint8_t> &hashValue)
414 {
415 ValueHashCalc hashCalc;
416 int errCode = hashCalc.Initialize();
417 if (errCode != E_OK) {
418 return -E_ERROR;
419 }
420
421 errCode = hashCalc.Update(value);
422 if (errCode != E_OK) {
423 return -E_ERROR;
424 }
425
426 errCode = hashCalc.GetResult(hashValue);
427 if (errCode != E_OK) {
428 return -E_ERROR;
429 }
430
431 return E_OK;
432 }
433
StringToUpper(std::string & str)434 void StringToUpper(std::string &str)
435 {
436 std::transform(str.cbegin(), str.cend(), str.begin(), [](unsigned char c) {
437 return std::toupper(c);
438 });
439 }
440
CalcHashKey(sqlite3_context * ctx,int argc,sqlite3_value ** argv)441 void CalcHashKey(sqlite3_context *ctx, int argc, sqlite3_value **argv)
442 {
443 // 1 means that the function only needs one parameter, namely key
444 if (ctx == nullptr || argc != 2 || argv == nullptr) { // 2 is params count
445 return;
446 }
447
448 int errCode;
449 std::vector<uint8_t> hashValue;
450 DistributedDB::CollateType collateType = static_cast<DistributedDB::CollateType>(sqlite3_value_int(argv[1]));
451 if (collateType == DistributedDB::CollateType::COLLATE_NOCASE) {
452 auto colChar = reinterpret_cast<const char *>(sqlite3_value_text(argv[0]));
453 if (colChar == nullptr) {
454 return;
455 }
456 std::string colStr(colChar);
457 StringToUpper(colStr);
458 std::vector<uint8_t> value;
459 value.assign(colStr.begin(), colStr.end());
460 errCode = CalcValueHash(value, hashValue);
461 } else if (collateType == DistributedDB::CollateType::COLLATE_RTRIM) {
462 auto colChar = reinterpret_cast<const char *>(sqlite3_value_text(argv[0]));
463 if (colChar == nullptr) {
464 return;
465 }
466 std::string colStr(colChar);
467 DBCommon::RTrim(colStr);
468 std::vector<uint8_t> value;
469 value.assign(colStr.begin(), colStr.end());
470 errCode = CalcValueHash(value, hashValue);
471 } else {
472 auto keyBlob = static_cast<const uint8_t *>(sqlite3_value_blob(argv[0]));
473 if (keyBlob == nullptr) {
474 sqlite3_result_error(ctx, "Parameters is invalid.", -1);
475 return;
476 }
477
478 int blobLen = sqlite3_value_bytes(argv[0]);
479 std::vector<uint8_t> value(keyBlob, keyBlob + blobLen);
480 errCode = CalcValueHash(value, hashValue);
481 }
482
483 if (errCode != E_OK) {
484 sqlite3_result_error(ctx, "Get hash value error.", -1);
485 return;
486 }
487 sqlite3_result_blob(ctx, hashValue.data(), hashValue.size(), SQLITE_TRANSIENT);
488 }
489
RegisterCalcHash(sqlite3 * db)490 int RegisterCalcHash(sqlite3 *db)
491 {
492 TransactFunc func;
493 func.xFunc = &CalcHashKey;
494 return RegisterFunction(db, "calc_hash", 2, nullptr, func); // 2 is params count
495 }
496
GetLocalTimeOffsetFromMeta(sqlite3 * db,TimeOffset & offset)497 int GetLocalTimeOffsetFromMeta(sqlite3 *db, TimeOffset &offset)
498 {
499 if (db == nullptr) {
500 return -E_ERROR;
501 }
502
503 sqlite3_stmt *stmt = nullptr;
504 int errCode = GetStatement(db, "SELECT value FROM naturalbase_rdb_aux_metadata WHERE key = ?", stmt);
505 if (errCode != E_OK) {
506 LOGE("Prepare meta data stmt failed. %d", errCode);
507 return -E_ERROR;
508 }
509
510 std::string keyStr = "localTimeOffset";
511 std::vector<uint8_t> key(keyStr.begin(), keyStr.end());
512 errCode = BindBlobToStatement(stmt, 1, key);
513 if (errCode != E_OK) {
514 (void)ResetStatement(stmt);
515 LOGE("Bind meta data stmt failed, Key: %s. %d", keyStr.c_str(), errCode);
516 return -E_ERROR;
517 }
518
519 std::vector<uint8_t> value;
520 errCode = StepWithRetry(stmt);
521 if (errCode == SQLITE_ROW) {
522 GetColumnBlobValue(stmt, 0, value);
523 } else if (errCode == SQLITE_DONE) {
524 (void)ResetStatement(stmt);
525 LOGE("Get meta data not found, Key: %s. %d", keyStr.c_str(), errCode);
526 return E_OK;
527 } else {
528 (void)ResetStatement(stmt);
529 LOGE("Get meta data failed, Key: %s. %d", keyStr.c_str(), errCode);
530 return -E_ERROR;
531 }
532
533 std::string valueStr(value.begin(), value.end());
534 int64_t result = std::strtoll(valueStr.c_str(), nullptr, STR_TO_LL_BY_DEVALUE);
535 if (errno != ERANGE && result != LLONG_MIN && result != LLONG_MAX) {
536 offset = result;
537 }
538 (void)ResetStatement(stmt);
539 LOGD("Get local time offset from meta: %" PRId64, offset);
540 return E_OK;
541 }
542
543 int GetCurrentMaxTimestamp(sqlite3 *db, Timestamp &maxTimestamp);
544
GetSysTime(sqlite3_context * ctx,int argc,sqlite3_value ** argv)545 void GetSysTime(sqlite3_context *ctx, int argc, sqlite3_value **argv)
546 {
547 if (ctx == nullptr || argc != 1 || argv == nullptr) { // 1: function need one parameter
548 return;
549 }
550
551 auto *db = static_cast<sqlite3 *>(sqlite3_user_data(ctx));
552 if (db == nullptr) {
553 sqlite3_result_error(ctx, "Sqlite context is invalid.", -1);
554 return;
555 }
556
557 std::function<Timestamp()> getDbMaxTimestamp = [db]() -> Timestamp {
558 Timestamp maxTimestamp = 0;
559 (void)GetCurrentMaxTimestamp(db, maxTimestamp);
560 return maxTimestamp;
561 };
562 std::function<Timestamp()> getDbLocalTimeOffset = [db]() -> Timestamp {
563 TimeOffset localTimeOffset = TimeHelper::BASE_OFFSET;
564 (void)GetLocalTimeOffsetFromMeta(db, localTimeOffset);
565 return localTimeOffset;
566 };
567
568 std::string identity;
569 GetDBIdentity(db, identity);
570 auto timeOffset = static_cast<TimeOffset>(sqlite3_value_int64(argv[0]));
571 (void)TimeHelperManager::GetInstance()->TimeSkew(identity, getDbLocalTimeOffset, timeOffset);
572 Timestamp currentTime = TimeHelperManager::GetInstance()->GetTime(identity, timeOffset, getDbMaxTimestamp,
573 getDbLocalTimeOffset);
574 sqlite3_result_int64(ctx, (sqlite3_int64)currentTime);
575 }
576
GetRawSysTime(sqlite3_context * ctx,int argc,sqlite3_value ** argv)577 void GetRawSysTime(sqlite3_context *ctx, int argc, sqlite3_value **argv)
578 {
579 if (ctx == nullptr || argc != 0 || argv == nullptr) { // 0: function need zero parameter
580 return;
581 }
582
583 uint64_t curTime = 0;
584 int errCode = TimeHelper::GetSysCurrentRawTime(curTime);
585 if (errCode != E_OK) {
586 sqlite3_result_error(ctx, "get raw sys time failed.", errCode);
587 return;
588 }
589 sqlite3_result_int64(ctx, (sqlite3_int64)(curTime));
590 }
591
GetLastTime(sqlite3_context * ctx,int argc,sqlite3_value ** argv)592 void GetLastTime(sqlite3_context *ctx, int argc, sqlite3_value **argv)
593 {
594 if (ctx == nullptr || argc != 0 || argv == nullptr) { // 0: function need zero parameter
595 return;
596 }
597
598 auto *db = static_cast<sqlite3 *>(sqlite3_user_data(ctx));
599 if (db == nullptr) {
600 sqlite3_result_error(ctx, "Sqlite context is invalid.", -1);
601 return;
602 }
603 std::string identity;
604 GetDBIdentity(db, identity);
605
606 sqlite3_result_int64(ctx, (sqlite3_int64)TimeHelperManager::GetInstance()->GetLastTime(identity));
607 }
608
GetHashString(const std::string & str,std::string & dst)609 int GetHashString(const std::string &str, std::string &dst)
610 {
611 std::vector<uint8_t> strVec;
612 strVec.assign(str.begin(), str.end());
613 std::vector<uint8_t> hashVec;
614 int errCode = CalcValueHash(strVec, hashVec);
615 if (errCode != E_OK) {
616 LOGE("calc hash value fail, %d", errCode);
617 return errCode;
618 }
619 dst.assign(hashVec.begin(), hashVec.end());
620 return E_OK;
621 }
622
GetDbFileName(sqlite3 * db,std::string & fileName)623 static bool GetDbFileName(sqlite3 *db, std::string &fileName)
624 {
625 if (db == nullptr) {
626 return false;
627 }
628
629 auto dbFilePath = sqlite3_db_filename(db, nullptr);
630 if (dbFilePath == nullptr) {
631 return false;
632 }
633 fileName = std::string(dbFilePath);
634 return true;
635 }
636
GetDbHashString(sqlite3 * db,std::string & hashFileName)637 static bool GetDbHashString(sqlite3 *db, std::string &hashFileName)
638 {
639 std::string fileName;
640 if (!GetDbFileName(db, fileName)) {
641 LOGE("Get db fileName failed.");
642 return false;
643 }
644 return GetHashString(fileName, hashFileName) == E_OK;
645 }
646
CloudDataChangedObserver(sqlite3_context * ctx,int argc,sqlite3_value ** argv)647 void CloudDataChangedObserver(sqlite3_context *ctx, int argc, sqlite3_value **argv)
648 {
649 if (ctx == nullptr || argc != 4 || argv == nullptr) { // 4 is param counts
650 return;
651 }
652 sqlite3 *db = static_cast<sqlite3 *>(sqlite3_user_data(ctx));
653 std::string hashFileName = "";
654 if (!GetDbHashString(db, hashFileName)) {
655 return;
656 }
657 auto tableNameChar = reinterpret_cast<const char *>(sqlite3_value_text(argv[0]));
658 if (tableNameChar == nullptr) {
659 return;
660 }
661 std::string tableName = static_cast<std::string>(tableNameChar);
662
663 uint64_t isTrackerChange = static_cast<uint64_t>(sqlite3_value_int(argv[3])); // 3 is param index
664 bool isExistObserver = false;
665 {
666 std::lock_guard<std::mutex> lock(g_clientObserverMutex);
667 auto it = g_clientObserverMap.find(hashFileName);
668 isExistObserver = (it != g_clientObserverMap.end());
669 }
670 {
671 std::lock_guard<std::mutex> lock(g_clientChangedDataMutex);
672 if (isExistObserver) {
673 auto itTable = g_clientChangedDataMap[hashFileName].tableData.find(tableName);
674 if (itTable != g_clientChangedDataMap[hashFileName].tableData.end()) {
675 itTable->second.isTrackedDataChange =
676 (static_cast<uint8_t>(itTable->second.isTrackedDataChange) | isTrackerChange) > 0;
677 } else {
678 DistributedDB::ChangeProperties properties = { .isTrackedDataChange = (isTrackerChange > 0) };
679 g_clientChangedDataMap[hashFileName].tableData.insert_or_assign(tableName, properties);
680 }
681 }
682 }
683 sqlite3_result_int64(ctx, static_cast<sqlite3_int64>(1));
684 }
685
JudgeIfGetRowid(sqlite3 * db,const std::string & tableName,std::string & type,bool & isRowid)686 int JudgeIfGetRowid(sqlite3 *db, const std::string &tableName, std::string &type, bool &isRowid)
687 {
688 if (db == nullptr) {
689 return -E_ERROR;
690 }
691 std::string checkPrimaryKeySql = "SELECT count(1), type FROM pragma_table_info('" + tableName;
692 checkPrimaryKeySql += "') WHERE pk = 1";
693 sqlite3_stmt *checkPrimaryKeyStmt = nullptr;
694 int errCode = GetStatement(db, checkPrimaryKeySql, checkPrimaryKeyStmt);
695 if (errCode != E_OK) {
696 LOGE("Prepare get primarykey info statement failed. err=%d", errCode);
697 return -E_ERROR;
698 }
699 errCode = SQLiteUtils::StepWithRetry(checkPrimaryKeyStmt);
700 if (errCode == SQLiteUtils::MapSQLiteErrno(SQLITE_ROW)) {
701 int count = sqlite3_column_int(checkPrimaryKeyStmt, 0);
702 GetColumnTextValue(checkPrimaryKeyStmt, 1, type);
703 isRowid = (count != 1) || (type != "TEXT" && type != "INT" && type != "INTEGER");
704 errCode = E_OK;
705 } else if (errCode == SQLiteUtils::MapSQLiteErrno(SQLITE_DONE)) {
706 errCode = E_OK;
707 } else {
708 errCode = SQLiteUtils::MapSQLiteErrno(errCode);
709 }
710 ResetStatement(checkPrimaryKeyStmt);
711 return errCode;
712 }
713
SaveChangedData(const std::string & hashFileName,const std::string & tableName,const std::string & columnName,const DistributedDB::Type & data,ChangeType option)714 void SaveChangedData(const std::string &hashFileName, const std::string &tableName, const std::string &columnName,
715 const DistributedDB::Type &data, ChangeType option)
716 {
717 if (option < ChangeType::OP_INSERT || option >= ChangeType::OP_BUTT) {
718 return;
719 }
720 std::lock_guard<std::mutex> lock(g_storeChangedDataMutex);
721 auto itTable = std::find_if(g_storeChangedDataMap[hashFileName].begin(), g_storeChangedDataMap[hashFileName].end(),
722 [tableName](DistributedDB::ChangedData changedData) {
723 return tableName == changedData.tableName;
724 });
725 if (itTable != g_storeChangedDataMap[hashFileName].end()) {
726 std::vector<Type> dataVec;
727 dataVec.push_back(data);
728 itTable->primaryData[option].push_back(dataVec);
729 } else {
730 DistributedDB::ChangedData changedData;
731 changedData.tableName = tableName;
732 changedData.field.push_back(columnName);
733 std::vector<DistributedDB::Type> dataVec;
734 dataVec.push_back(data);
735 changedData.primaryData[option].push_back(dataVec);
736 g_storeChangedDataMap[hashFileName].push_back(changedData);
737 }
738 }
739
DataChangedObserver(sqlite3_context * ctx,int argc,sqlite3_value ** argv)740 void DataChangedObserver(sqlite3_context *ctx, int argc, sqlite3_value **argv)
741 {
742 if (ctx == nullptr || argc != 4 || argv == nullptr) { // 4 is param counts
743 return;
744 }
745 sqlite3 *db = static_cast<sqlite3 *>(sqlite3_user_data(ctx));
746 std::string hashFileName = "";
747 if (!GetDbHashString(db, hashFileName)) {
748 return;
749 }
750 bool isExistObserver = false;
751 {
752 std::lock_guard<std::mutex> lock(g_storeObserverMutex);
753 auto it = g_storeObserverMap.find(hashFileName);
754 isExistObserver = (it != g_storeObserverMap.end());
755 }
756 if (!isExistObserver) {
757 return;
758 }
759 auto tableNameChar = reinterpret_cast<const char *>(sqlite3_value_text(argv[0]));
760 if (tableNameChar == nullptr) {
761 return;
762 }
763 std::string tableName = static_cast<std::string>(tableNameChar);
764 auto columnNameChar = reinterpret_cast<const char *>(sqlite3_value_text(argv[1])); // 1 is param index
765 if (columnNameChar == nullptr) {
766 return;
767 }
768 std::string columnName = static_cast<std::string>(columnNameChar);
769 DistributedDB::Type data;
770 std::string type = "";
771 bool isRowid = false;
772 int errCode = JudgeIfGetRowid(db, tableName, type, isRowid);
773 if (errCode != E_OK) {
774 sqlite3_result_error(ctx, "Get primary key info error.", -1);
775 return;
776 }
777 if (!isRowid && type == "TEXT") {
778 auto dataChar = reinterpret_cast<const char *>(sqlite3_value_text(argv[2])); // 2 is param index
779 if (dataChar == nullptr) {
780 return;
781 }
782 data = static_cast<std::string>(dataChar);
783 } else {
784 data = static_cast<int64_t>(sqlite3_value_int64(argv[2])); // 2 is param index
785 }
786 ChangeType option = static_cast<ChangeType>(sqlite3_value_int64(argv[3])); // 3 is param index
787 SaveChangedData(hashFileName, tableName, columnName, data, option);
788 sqlite3_result_int64(ctx, static_cast<sqlite3_int64>(1)); // 1 is result ok
789 }
790
GetInsertTrigger(const std::string & tableName,bool isRowid,const std::string & primaryKey)791 std::string GetInsertTrigger(const std::string &tableName, bool isRowid, const std::string &primaryKey)
792 {
793 std::string insertTrigger = "CREATE TEMP TRIGGER IF NOT EXISTS ";
794 insertTrigger += "naturalbase_rdb_" + tableName + "_local_ON_INSERT AFTER INSERT\n";
795 insertTrigger += "ON '" + tableName + "'\n";
796 insertTrigger += "BEGIN\n";
797 if (isRowid || primaryKey.empty()) { // LCOV_EXCL_BR_LINE
798 insertTrigger += "SELECT data_change('" + tableName + "', 'rowid', NEW._rowid_, 0);\n";
799 } else {
800 insertTrigger += "SELECT data_change('" + tableName + "', ";
801 insertTrigger += "(SELECT name as a FROM pragma_table_info('" + tableName + "') WHERE pk=1), ";
802 insertTrigger += "NEW." + primaryKey + ", 0);\n";
803 }
804 insertTrigger += "END;";
805 return insertTrigger;
806 }
807
GetUpdateTrigger(const std::string & tableName,bool isRowid,const std::string & primaryKey)808 std::string GetUpdateTrigger(const std::string &tableName, bool isRowid, const std::string &primaryKey)
809 {
810 std::string updateTrigger = "CREATE TEMP TRIGGER IF NOT EXISTS ";
811 updateTrigger += "naturalbase_rdb_" + tableName + "_local_ON_UPDATE AFTER UPDATE\n";
812 updateTrigger += "ON '" + tableName + "'\n";
813 updateTrigger += "BEGIN\n";
814 if (isRowid || primaryKey.empty()) { // LCOV_EXCL_BR_LINE
815 updateTrigger += "SELECT data_change('" + tableName + "', 'rowid', NEW._rowid_, 1);\n";
816 } else {
817 updateTrigger += "SELECT data_change('" + tableName + "', ";
818 updateTrigger += "(SELECT name as a FROM pragma_table_info('" + tableName + "') WHERE pk=1), ";
819 updateTrigger += "NEW." + primaryKey + ", 1);\n";
820 }
821 updateTrigger += "END;";
822 return updateTrigger;
823 }
824
GetDeleteTrigger(const std::string & tableName,bool isRowid,const std::string & primaryKey)825 std::string GetDeleteTrigger(const std::string &tableName, bool isRowid, const std::string &primaryKey)
826 {
827 std::string deleteTrigger = "CREATE TEMP TRIGGER IF NOT EXISTS ";
828 deleteTrigger += "naturalbase_rdb_" + tableName + "_local_ON_DELETE AFTER DELETE\n";
829 deleteTrigger += "ON '" + tableName + "'\n";
830 deleteTrigger += "BEGIN\n";
831 if (isRowid || primaryKey.empty()) { // LCOV_EXCL_BR_LINE
832 deleteTrigger += "SELECT data_change('" + tableName + "', 'rowid', OLD._rowid_, 2);\n";
833 } else {
834 deleteTrigger += "SELECT data_change('" + tableName + "', ";
835 deleteTrigger += "(SELECT name as a FROM pragma_table_info('" + tableName + "') WHERE pk=1), ";
836 deleteTrigger += "OLD." + primaryKey + ", 2);\n";
837 }
838 deleteTrigger += "END;";
839 return deleteTrigger;
840 }
841
GetPrimaryKeyName(sqlite3 * db,const std::string & tableName,std::string & primaryKey)842 int GetPrimaryKeyName(sqlite3 *db, const std::string &tableName, std::string &primaryKey)
843 {
844 if (db == nullptr) {
845 return -E_ERROR;
846 }
847 std::string sql = "SELECT name FROM pragma_table_info('";
848 sql += tableName + "') WHERE pk = 1";
849 sqlite3_stmt *stmt = nullptr;
850 int errCode = GetStatement(db, sql, stmt);
851 if (errCode != E_OK) {
852 LOGE("Prepare get primary key name statement failed. err=%d", errCode);
853 return -E_ERROR;
854 }
855 while ((errCode = StepWithRetry(stmt)) != SQLITE_DONE) {
856 if (errCode != SQLITE_ROW) {
857 ResetStatement(stmt);
858 LOGE("Get primary key name step statement failed.");
859 return -E_ERROR;
860 }
861 GetColumnTextValue(stmt, 0, primaryKey);
862 }
863 ResetStatement(stmt);
864 return E_OK;
865 }
866
GetTriggerSqls(sqlite3 * db,const std::map<std::string,bool> & tableInfos,std::vector<std::string> & triggerSqls)867 int GetTriggerSqls(sqlite3 *db, const std::map<std::string, bool> &tableInfos, std::vector<std::string> &triggerSqls)
868 {
869 for (const auto &tableInfo : tableInfos) {
870 std::string primaryKey = "";
871 if (!tableInfo.second) {
872 int errCode = GetPrimaryKeyName(db, tableInfo.first, primaryKey);
873 if (errCode != E_OK) {
874 return errCode;
875 }
876 }
877 std::string sql = GetInsertTrigger(tableInfo.first, tableInfo.second, primaryKey);
878 triggerSqls.push_back(sql);
879 sql = GetUpdateTrigger(tableInfo.first, tableInfo.second, primaryKey);
880 triggerSqls.push_back(sql);
881 sql = GetDeleteTrigger(tableInfo.first, tableInfo.second, primaryKey);
882 triggerSqls.push_back(sql);
883 }
884 return E_OK;
885 }
886
AuthorizerCallback(void * data,int operation,const char * tableNameChar,const char *,const char *,const char *)887 int AuthorizerCallback(void *data, int operation, const char *tableNameChar, const char *, const char *, const char *)
888 {
889 if (operation != SQLITE_CREATE_TABLE || tableNameChar == nullptr) {
890 return SQLITE_OK;
891 }
892 std::lock_guard<std::mutex> clientCreateTableLock(g_clientCreateTableMutex);
893 std::string tableName = static_cast<std::string>(tableNameChar);
894 if (ParamCheckUtils::CheckRelationalTableName(tableName) && tableName.find("sqlite_") != 0 &&
895 tableName.find("naturalbase_") != 0) {
896 g_clientCreateTable.insert(tableName);
897 }
898 return SQLITE_OK;
899 }
900
ClientObserverCallback(const std::string & hashFileName)901 void ClientObserverCallback(const std::string &hashFileName)
902 {
903 ClientObserver clientObserver;
904 {
905 std::lock_guard<std::mutex> clientObserverLock(g_clientObserverMutex);
906 auto it = g_clientObserverMap.find(hashFileName);
907 if (it != g_clientObserverMap.end() && it->second != nullptr) {
908 clientObserver = it->second;
909 } else {
910 return;
911 }
912 }
913 std::lock_guard<std::mutex> clientChangedDataLock(g_clientChangedDataMutex);
914 auto it = g_clientChangedDataMap.find(hashFileName);
915 if (it != g_clientChangedDataMap.end() && !it->second.tableData.empty()) {
916 ClientChangedData clientChangedData = g_clientChangedDataMap[hashFileName];
917 ConcurrentAdapter::ScheduleTask([clientObserver, clientChangedData] {
918 ClientChangedData taskClientChangedData = clientChangedData;
919 clientObserver(taskClientChangedData);
920 });
921 g_clientChangedDataMap[hashFileName].tableData.clear();
922 }
923 }
924
TriggerObserver(const std::vector<std::shared_ptr<StoreObserver>> & storeObservers,const std::string & hashFileName)925 void TriggerObserver(const std::vector<std::shared_ptr<StoreObserver>> &storeObservers, const std::string &hashFileName)
926 {
927 std::lock_guard<std::mutex> storeChangedDataLock(g_storeChangedDataMutex);
928 for (const auto &storeObserver : storeObservers) {
929 auto it = g_storeChangedDataMap.find(hashFileName);
930 if (it != g_storeChangedDataMap.end() && !it->second.empty()) {
931 std::vector<DistributedDB::ChangedData> storeChangedData = g_storeChangedDataMap[hashFileName];
932 storeObserver->OnChange(std::move(storeChangedData));
933 }
934 }
935 g_storeChangedDataMap[hashFileName].clear();
936 }
937
StoreObserverCallback(sqlite3 * db,const std::string & hashFileName)938 void StoreObserverCallback(sqlite3 *db, const std::string &hashFileName)
939 {
940 std::vector<std::shared_ptr<StoreObserver>> storeObserver;
941 {
942 std::lock_guard<std::mutex> storeObserverLock(g_storeObserverMutex);
943 auto it = g_storeObserverMap.find(hashFileName);
944 if (it != g_storeObserverMap.end() && !it->second.empty()) {
945 std::copy(it->second.begin(), it->second.end(), std::back_inserter(storeObserver));
946 } else {
947 return;
948 }
949 }
950 TriggerObserver(storeObserver, hashFileName);
951 std::map<std::string, bool> tableInfos;
952 {
953 std::lock_guard<std::mutex> clientCreateTableLock(g_clientCreateTableMutex);
954 if (g_clientCreateTable.empty()) {
955 return;
956 }
957 for (const auto &tableName : g_clientCreateTable) {
958 bool isRowid = true;
959 std::string type = "";
960 JudgeIfGetRowid(db, tableName, type, isRowid);
961 tableInfos.insert(std::make_pair(tableName, isRowid));
962 }
963 g_clientCreateTable.clear();
964 }
965 std::vector<std::string> triggerSqls;
966 int errCode = GetTriggerSqls(db, tableInfos, triggerSqls);
967 if (errCode != E_OK) {
968 LOGE("Get data change trigger sql failed %d", errCode);
969 return;
970 }
971 for (const auto &sql : triggerSqls) {
972 errCode = SQLiteUtils::ExecuteRawSQL(db, sql);
973 if (errCode != E_OK) {
974 LOGE("Create data change trigger failed %d", errCode);
975 return;
976 }
977 }
978 return;
979 }
980
LogCommitHookCallback(void * data,sqlite3 * db,const char * zDb,int size)981 int LogCommitHookCallback(void *data, sqlite3 *db, const char *zDb, int size)
982 {
983 std::string fileName;
984 if (!GetDbFileName(db, fileName)) {
985 return 0;
986 }
987 std::string hashFileName;
988 int errCode = GetHashString(fileName, hashFileName);
989 if (errCode != E_OK) {
990 return 0;
991 }
992 ClientObserverCallback(hashFileName);
993 StoreObserverCallback(db, hashFileName);
994 return 0;
995 }
996
RollbackHookCallback(void * data)997 void RollbackHookCallback(void* data)
998 {
999 sqlite3 *db = static_cast<sqlite3 *>(data);
1000 std::string fileName;
1001 if (!GetDbFileName(db, fileName)) {
1002 return;
1003 }
1004 std::string hashFileName;
1005 int errCode = GetHashString(fileName, hashFileName);
1006 if (errCode != E_OK) {
1007 return;
1008 }
1009 std::lock_guard<std::mutex> clientChangedDataLock(g_clientChangedDataMutex);
1010 auto it = g_clientChangedDataMap.find(hashFileName);
1011 if (it != g_clientChangedDataMap.end() && !it->second.tableData.empty()) {
1012 g_clientChangedDataMap[hashFileName].tableData.clear();
1013 }
1014 }
1015
RegisterGetSysTime(sqlite3 * db)1016 int RegisterGetSysTime(sqlite3 *db)
1017 {
1018 TransactFunc func;
1019 func.xFunc = &GetSysTime;
1020 return RegisterFunction(db, "get_sys_time", 1, db, func);
1021 }
1022
RegisterGetLastTime(sqlite3 * db)1023 int RegisterGetLastTime(sqlite3 *db)
1024 {
1025 TransactFunc func;
1026 func.xFunc = &GetLastTime;
1027 return RegisterFunction(db, "get_last_time", 0, db, func);
1028 }
1029
RegisterGetRawSysTime(sqlite3 * db)1030 int RegisterGetRawSysTime(sqlite3 *db)
1031 {
1032 TransactFunc func;
1033 func.xFunc = &GetRawSysTime;
1034 return RegisterFunction(db, "get_raw_sys_time", 0, nullptr, func);
1035 }
1036
RegisterCloudDataChangeObserver(sqlite3 * db)1037 int RegisterCloudDataChangeObserver(sqlite3 *db)
1038 {
1039 TransactFunc func;
1040 func.xFunc = &CloudDataChangedObserver;
1041 return RegisterFunction(db, "client_observer", 4, db, func); // 4 is param counts
1042 }
1043
RegisterDataChangeObserver(sqlite3 * db)1044 int RegisterDataChangeObserver(sqlite3 *db)
1045 {
1046 TransactFunc func;
1047 func.xFunc = &DataChangedObserver;
1048 return RegisterFunction(db, "data_change", 4, db, func); // 4 is param counts
1049 }
1050
RegisterCommitAndRollbackHook(sqlite3 * db)1051 void RegisterCommitAndRollbackHook(sqlite3 *db)
1052 {
1053 sqlite3_set_authorizer(db, AuthorizerCallback, nullptr);
1054 sqlite3_wal_hook(db, LogCommitHookCallback, db);
1055 sqlite3_rollback_hook(db, RollbackHookCallback, db);
1056 }
1057
ResetStatement(sqlite3_stmt * & stmt)1058 int ResetStatement(sqlite3_stmt *&stmt)
1059 {
1060 if (stmt == nullptr || sqlite3_finalize(stmt) != SQLITE_OK) { // LCOV_EXCL_BR_LINE
1061 return -E_ERROR;
1062 }
1063 stmt = nullptr;
1064 return E_OK;
1065 }
1066
GetStatement(sqlite3 * db,const std::string & sql,sqlite3_stmt * & stmt)1067 int GetStatement(sqlite3 *db, const std::string &sql, sqlite3_stmt *&stmt)
1068 {
1069 int errCode = sqlite3_prepare_v2(db, sql.c_str(), -1, &stmt, nullptr);
1070 if (errCode != SQLITE_OK) {
1071 (void)ResetStatement(stmt);
1072 LOGE("Get stmt failed. %d", errCode);
1073 return -E_ERROR;
1074 }
1075 return E_OK;
1076 }
1077
ExecuteRawSQL(sqlite3 * db,const std::string & sql)1078 int ExecuteRawSQL(sqlite3 *db, const std::string &sql)
1079 {
1080 if (db == nullptr) {
1081 return -E_ERROR;
1082 }
1083 char *errMsg = nullptr;
1084 int errCode = sqlite3_exec(db, sql.c_str(), nullptr, nullptr, &errMsg);
1085 if (errCode != SQLITE_OK) {
1086 errCode = -E_ERROR;
1087 }
1088
1089 if (errMsg != nullptr) {
1090 sqlite3_free(errMsg);
1091 errMsg = nullptr;
1092 }
1093 return errCode;
1094 }
1095
StepWithRetry(sqlite3_stmt * stmt)1096 int StepWithRetry(sqlite3_stmt *stmt)
1097 {
1098 if (stmt == nullptr) {
1099 return -E_ERROR;
1100 }
1101 int errCode = sqlite3_step(stmt);
1102 if (errCode != SQLITE_DONE && errCode != SQLITE_ROW) {
1103 return -E_ERROR;
1104 }
1105 return errCode;
1106 }
1107
BindBlobToStatement(sqlite3_stmt * stmt,int index,const std::vector<uint8_t> & value,bool permEmpty)1108 int BindBlobToStatement(sqlite3_stmt *stmt, int index, const std::vector<uint8_t> &value, bool permEmpty)
1109 {
1110 if (stmt == nullptr || (value.empty() && !permEmpty)) { // LCOV_EXCL_BR_LINE
1111 return -E_ERROR;
1112 }
1113 int errCode;
1114 if (value.empty()) {
1115 errCode = sqlite3_bind_zeroblob(stmt, index, -1); // -1: zero-length blob
1116 } else {
1117 errCode = sqlite3_bind_blob(stmt, index, static_cast<const void*>(value.data()), value.size(),
1118 SQLITE_TRANSIENT);
1119 }
1120 return errCode == E_OK ? E_OK : -E_ERROR;
1121 }
1122
GetColumnTextValue(sqlite3_stmt * stmt,int index,std::string & value)1123 int GetColumnTextValue(sqlite3_stmt *stmt, int index, std::string &value)
1124 {
1125 if (stmt == nullptr) {
1126 return -E_ERROR;
1127 }
1128 const unsigned char *val = sqlite3_column_text(stmt, index);
1129 value = (val != nullptr) ? std::string(reinterpret_cast<const char *>(val)) : std::string();
1130 return E_OK;
1131 }
1132
GetColumnBlobValue(sqlite3_stmt * stmt,int index,std::vector<uint8_t> & value)1133 int GetColumnBlobValue(sqlite3_stmt *stmt, int index, std::vector<uint8_t> &value)
1134 {
1135 if (stmt == nullptr) {
1136 return -E_ERROR;
1137 }
1138
1139 int keySize = sqlite3_column_bytes(stmt, index);
1140 if (keySize < 0) {
1141 value.resize(0);
1142 return E_OK;
1143 }
1144 auto keyRead = static_cast<const uint8_t *>(sqlite3_column_blob(stmt, index));
1145 if (keySize == 0 || keyRead == nullptr) {
1146 value.resize(0);
1147 } else {
1148 if (keySize > MAX_BLOB_READ_SIZE) {
1149 keySize = MAX_BLOB_READ_SIZE + 1;
1150 }
1151 value.resize(keySize);
1152 value.assign(keyRead, keyRead + keySize);
1153 }
1154 return E_OK;
1155 }
1156
GetCurrentMaxTimestamp(sqlite3 * db,Timestamp & maxTimestamp)1157 int GetCurrentMaxTimestamp(sqlite3 *db, Timestamp &maxTimestamp)
1158 {
1159 if (db == nullptr) {
1160 return -E_ERROR;
1161 }
1162 std::string checkTableSql = "SELECT name FROM sqlite_master WHERE type = 'table' AND " \
1163 "name LIKE 'naturalbase_rdb_aux_%_log';";
1164 sqlite3_stmt *checkTableStmt = nullptr;
1165 int errCode = GetStatement(db, checkTableSql, checkTableStmt);
1166 if (errCode != E_OK) {
1167 LOGE("Prepare get max log timestamp statement failed. err=%d", errCode);
1168 return -E_ERROR;
1169 }
1170 while ((errCode = StepWithRetry(checkTableStmt)) != SQLITE_DONE) {
1171 if (errCode != SQLITE_ROW) {
1172 ResetStatement(checkTableStmt);
1173 return -E_ERROR;
1174 }
1175 std::string logTableName;
1176 GetColumnTextValue(checkTableStmt, 0, logTableName);
1177 if (logTableName.empty()) {
1178 continue;
1179 }
1180
1181 std::string getMaxTimestampSql = "SELECT MAX(timestamp) FROM " + logTableName + ";";
1182 sqlite3_stmt *getTimeStmt = nullptr;
1183 errCode = GetStatement(db, getMaxTimestampSql, getTimeStmt);
1184 if (errCode != E_OK) {
1185 continue;
1186 }
1187 errCode = StepWithRetry(getTimeStmt);
1188 if (errCode != SQLITE_ROW) {
1189 ResetStatement(getTimeStmt);
1190 continue;
1191 }
1192 auto tableMaxTimestamp = static_cast<Timestamp>(sqlite3_column_int64(getTimeStmt, 0));
1193 maxTimestamp = (maxTimestamp > tableMaxTimestamp) ? maxTimestamp : tableMaxTimestamp;
1194 ResetStatement(getTimeStmt);
1195 }
1196 ResetStatement(checkTableStmt);
1197 return E_OK;
1198 }
1199
CheckTableExists(sqlite3 * db,const std::string & tableName)1200 bool CheckTableExists(sqlite3 *db, const std::string &tableName)
1201 {
1202 sqlite3_stmt *stmt = nullptr;
1203 std::string sql = "SELECT count(*) FROM sqlite_master WHERE type='table' AND name='" + tableName + "';";
1204 if (sqlite3_prepare_v2(db, sql.c_str(), -1, &stmt, nullptr) != SQLITE_OK) { // LCOV_EXCL_BR_LINE
1205 (void)sqlite3_finalize(stmt);
1206 return false;
1207 }
1208
1209 bool isLogTblExists = false;
1210 if (sqlite3_step(stmt) == SQLITE_ROW && static_cast<bool>(sqlite3_column_int(stmt, 0))) { // LCOV_EXCL_BR_LINE
1211 isLogTblExists = true;
1212 }
1213 (void)sqlite3_finalize(stmt);
1214 return isLogTblExists;
1215 }
1216
GetTableSyncType(sqlite3 * db,const std::string & tableName,std::string & tableType)1217 int GetTableSyncType(sqlite3 *db, const std::string &tableName, std::string &tableType)
1218 {
1219 const char *selectSql = "SELECT value FROM naturalbase_rdb_aux_metadata WHERE key=?;";
1220 sqlite3_stmt *statement = nullptr;
1221 int errCode = sqlite3_prepare_v2(db, selectSql, -1, &statement, nullptr);
1222 if (errCode != SQLITE_OK) {
1223 (void)sqlite3_finalize(statement);
1224 return -E_ERROR;
1225 }
1226
1227 std::string keyStr = SYNC_TABLE_TYPE + tableName;
1228 std::vector<uint8_t> key(keyStr.begin(), keyStr.end());
1229 if (sqlite3_bind_blob(statement, 1, static_cast<const void *>(key.data()), key.size(),
1230 SQLITE_TRANSIENT) != SQLITE_OK) { // LCOV_EXCL_BR_LINE
1231 return -E_ERROR;
1232 }
1233
1234 if (sqlite3_step(statement) == SQLITE_ROW) {
1235 std::vector<uint8_t> value;
1236 if (GetColumnBlobValue(statement, 0, value) == E_OK) {
1237 tableType.assign(value.begin(), value.end());
1238 (void)sqlite3_finalize(statement);
1239 return E_OK;
1240 } else {
1241 (void)sqlite3_finalize(statement);
1242 return -E_ERROR;
1243 }
1244 } else if (sqlite3_step(statement) != SQLITE_DONE) {
1245 (void)sqlite3_finalize(statement);
1246 return -E_ERROR;
1247 }
1248 (void)sqlite3_finalize(statement);
1249 tableType = DEVICE_TYPE;
1250 return E_OK;
1251 }
1252
HandleDropCloudSyncTable(sqlite3 * db,const std::string & tableName)1253 void HandleDropCloudSyncTable(sqlite3 *db, const std::string &tableName)
1254 {
1255 std::string logTblName = "naturalbase_rdb_aux_" + tableName + "_log";
1256 std::string sql = "UPDATE " + logTblName + " SET data_key=-1, flag=0x03, timestamp=get_raw_sys_time();";
1257 (void)sqlite3_exec(db, sql.c_str(), nullptr, nullptr, nullptr);
1258 std::string keyStr = SYNC_TABLE_TYPE + tableName;
1259 std::vector<uint8_t> key(keyStr.begin(), keyStr.end());
1260 sql = "DELETE FROM naturalbase_rdb_aux_metadata WHERE key = ?;";
1261 sqlite3_stmt *statement = nullptr;
1262 int errCode = sqlite3_prepare_v2(db, sql.c_str(), -1, &statement, nullptr);
1263 if (errCode != SQLITE_OK) {
1264 (void)sqlite3_finalize(statement);
1265 return;
1266 }
1267
1268 if (sqlite3_bind_blob(statement, 1, static_cast<const void *>(key.data()), key.size(),
1269 SQLITE_TRANSIENT) != SQLITE_OK) { // LCOV_EXCL_BR_LINE
1270 (void)sqlite3_finalize(statement);
1271 return;
1272 }
1273 (void)sqlite3_step(statement);
1274 (void)sqlite3_finalize(statement);
1275 }
1276
HandleDropLogicDeleteData(sqlite3 * db,const std::string & tableName,uint64_t cursor)1277 int HandleDropLogicDeleteData(sqlite3 *db, const std::string &tableName, uint64_t cursor)
1278 {
1279 std::string logTblName = DBCommon::GetLogTableName(tableName);
1280 std::string sql = "INSERT OR REPLACE INTO " + DBConstant::RELATIONAL_PREFIX + "metadata" +
1281 " VALUES ('log_trigger_switch', 'false')";
1282 int errCode = sqlite3_exec(db, sql.c_str(), nullptr, nullptr, nullptr);
1283 if (errCode != SQLITE_OK) {
1284 LOGE("close log_trigger_switch failed. %d", errCode);
1285 return errCode;
1286 }
1287 sql = "DELETE FROM " + tableName + " WHERE _rowid_ IN (SELECT data_key FROM " + logTblName + " WHERE "
1288 " flag&0x08=0x08" + (cursor == 0 ? ");" : " AND cursor <= '" + std::to_string(cursor) + "');");
1289 errCode = sqlite3_exec(db, sql.c_str(), nullptr, nullptr, nullptr);
1290 if (errCode != SQLITE_OK) {
1291 LOGE("delete logic deletedData failed. %d", errCode);
1292 return errCode;
1293 }
1294 sql = "DELETE FROM " + logTblName + " WHERE (flag&0x08=0x08 " +
1295 (cursor == 0 ? ");" : " AND cursor <= '" + std::to_string(cursor) + "');");
1296 errCode = sqlite3_exec(db, sql.c_str(), nullptr, nullptr, nullptr);
1297 if (errCode != SQLITE_OK) {
1298 LOGE("delete logic delete log failed. %d", errCode);
1299 return errCode;
1300 }
1301 sql = "INSERT OR REPLACE INTO " + DBConstant::RELATIONAL_PREFIX + "metadata" +
1302 " VALUES ('log_trigger_switch', 'true')";
1303 errCode = sqlite3_exec(db, sql.c_str(), nullptr, nullptr, nullptr);
1304 if (errCode != SQLITE_OK) {
1305 LOGE("open log_trigger_switch failed. %d", errCode);
1306 }
1307 return errCode;
1308 }
1309
SaveDeleteFlagToDB(sqlite3 * db,const std::string & tableName)1310 int SaveDeleteFlagToDB(sqlite3 *db, const std::string &tableName)
1311 {
1312 std::string keyStr = DBConstant::TABLE_IS_DROPPED + tableName;
1313 Key key;
1314 DBCommon::StringToVector(keyStr, key);
1315 Value value;
1316 DBCommon::StringToVector("1", value); // 1 means delete
1317 std::string sql = "INSERT OR REPLACE INTO naturalbase_rdb_aux_metadata VALUES(?, ?);";
1318 sqlite3_stmt *statement = nullptr;
1319 int errCode = sqlite3_prepare_v2(db, sql.c_str(), -1, &statement, nullptr);
1320 if (errCode != SQLITE_OK) {
1321 LOGE("[SaveDeleteFlagToDB] prepare statement failed, %d", errCode);
1322 return -E_ERROR;
1323 }
1324
1325 if (sqlite3_bind_blob(statement, 1, static_cast<const void *>(key.data()), key.size(),
1326 SQLITE_TRANSIENT) != SQLITE_OK) { // LCOV_EXCL_BR_LINE
1327 (void)sqlite3_finalize(statement);
1328 LOGE("[SaveDeleteFlagToDB] bind key failed, %d", errCode);
1329 return -E_ERROR;
1330 }
1331 if (sqlite3_bind_blob(statement, 2, static_cast<const void *>(value.data()), value.size(), // 2 is column index
1332 SQLITE_TRANSIENT) != SQLITE_OK) { // LCOV_EXCL_BR_LINE
1333 (void)sqlite3_finalize(statement);
1334 LOGE("[SaveDeleteFlagToDB] bind value failed, %d", errCode);
1335 return -E_ERROR;
1336 }
1337 errCode = sqlite3_step(statement);
1338 if (errCode != SQLITE_DONE) {
1339 LOGE("[SaveDeleteFlagToDB] step failed, %d", errCode);
1340 (void)sqlite3_finalize(statement);
1341 return -E_ERROR;
1342 }
1343 (void)sqlite3_finalize(statement);
1344 return E_OK;
1345 }
1346
ClearTheLogAfterDropTable(sqlite3 * db,const char * tableName,const char * schemaName)1347 void ClearTheLogAfterDropTable(sqlite3 *db, const char *tableName, const char *schemaName)
1348 {
1349 if (db == nullptr || tableName == nullptr || schemaName == nullptr) {
1350 return;
1351 }
1352 auto filePath = sqlite3_db_filename(db, schemaName);
1353 if (filePath == nullptr) {
1354 return;
1355 }
1356 std::string fileName = std::string(filePath);
1357 Timestamp dropTimeStamp = TimeHelperManager::GetInstance()->GetTime(fileName, 0, nullptr, nullptr);
1358 std::string tableStr = std::string(tableName);
1359 std::string logTblName = DBCommon::GetLogTableName(tableStr);
1360 if (CheckTableExists(db, logTblName)) {
1361 if (SaveDeleteFlagToDB(db, tableStr) != E_OK) {
1362 // the failure of this step does not affect the following step, so we just write log
1363 LOGW("[ClearTheLogAfterDropTable] save delete flag failed.");
1364 }
1365 std::string tableType = DEVICE_TYPE;
1366 if (GetTableSyncType(db, tableStr, tableType) != E_OK) {
1367 return;
1368 }
1369 if (tableType == DEVICE_TYPE) {
1370 RegisterGetSysTime(db);
1371 RegisterGetLastTime(db);
1372 std::string sql = "UPDATE " + logTblName + " SET data_key=-1, flag=0x03, timestamp=get_sys_time(0) "
1373 "WHERE flag&0x03=0x02 AND timestamp<" + std::to_string(dropTimeStamp);
1374 (void)sqlite3_exec(db, sql.c_str(), nullptr, nullptr, nullptr);
1375 } else {
1376 HandleDropCloudSyncTable(db, tableStr);
1377 }
1378 }
1379 }
1380
CheckUnLockingDataExists(sqlite3 * db,const std::string & tableName)1381 bool CheckUnLockingDataExists(sqlite3 *db, const std::string &tableName)
1382 {
1383 sqlite3_stmt *stmt = nullptr;
1384 std::string sql = "SELECT count(1) FROM " + tableName + " WHERE status=1";
1385 if (sqlite3_prepare_v2(db, sql.c_str(), -1, &stmt, nullptr) != SQLITE_OK) { // LCOV_EXCL_BR_LINE
1386 return false;
1387 }
1388
1389 bool isExists = false;
1390 if ((sqlite3_step(stmt) == SQLITE_ROW) && (sqlite3_column_int(stmt, 0) > 0)) { // LCOV_EXCL_BR_LINE
1391 isExists = true;
1392 }
1393 (void)sqlite3_finalize(stmt);
1394 return isExists;
1395 }
1396
HandleDataStatus(sqlite3 * db,const std::string & tableName,const std::vector<std::vector<uint8_t>> & hashKey,bool isLock)1397 int HandleDataStatus(sqlite3 *db, const std::string &tableName, const std::vector<std::vector<uint8_t>> &hashKey,
1398 bool isLock)
1399 {
1400 std::string sql = "UPDATE " + tableName + " SET " + (isLock ? CloudDbConstant::TO_LOCK :
1401 CloudDbConstant::TO_UNLOCK) + " WHERE hash_key in (";
1402 for (size_t i = 0; i < hashKey.size(); i++) {
1403 sql += "?,";
1404 }
1405 sql.pop_back();
1406 sql += ");";
1407
1408 sqlite3_stmt *stmt = nullptr;
1409 int errCode = GetStatement(db, sql, stmt);
1410 if (errCode != E_OK) {
1411 LOGE("Prepare handle status stmt failed:%d, isLock:%d", errCode, isLock);
1412 return errCode;
1413 }
1414 int index = 1;
1415 for (const auto &hash: hashKey) {
1416 errCode = BindBlobToStatement(stmt, index++, hash);
1417 if (errCode != E_OK) {
1418 (void)ResetStatement(stmt);
1419 LOGE("Bind handle status stmt failed:%d, index:%d, isLock:%d", errCode, index, isLock);
1420 return errCode;
1421 }
1422 }
1423 errCode = StepWithRetry(stmt);
1424 (void)ResetStatement(stmt);
1425 if (errCode == SQLITE_DONE) {
1426 if (!isLock && CheckUnLockingDataExists(db, tableName)) {
1427 return -E_WAIT_COMPENSATED_SYNC;
1428 }
1429 if (sqlite3_changes(db) == 0) {
1430 return -E_NOT_FOUND;
1431 }
1432 } else {
1433 LOGE("step handle status failed:%d, isLock:%d", errCode, isLock);
1434 return -E_ERROR;
1435 }
1436 return E_OK;
1437 }
1438
HandleDataLock(const std::string & tableName,const std::vector<std::vector<uint8_t>> & hashKey,sqlite3 * db,bool isLock)1439 DistributedDB::DBStatus HandleDataLock(const std::string &tableName, const std::vector<std::vector<uint8_t>> &hashKey,
1440 sqlite3 *db, bool isLock)
1441 {
1442 std::string fileName;
1443 if (!GetDbFileName(db, fileName) || tableName.empty() || hashKey.empty()) {
1444 return DistributedDB::INVALID_ARGS;
1445 }
1446 std::string logTblName = DBCommon::GetLogTableName(tableName);
1447 if (!CheckTableExists(db, logTblName)) {
1448 return DistributedDB::INVALID_ARGS;
1449 }
1450 int errCode = SQLiteUtils::BeginTransaction(db, TransactType::IMMEDIATE);
1451 if (errCode != DistributedDB::E_OK) {
1452 LOGE("begin transaction failed before lock data:%d, isLock:%d", errCode, isLock);
1453 return DistributedDB::TransferDBErrno(errCode);
1454 }
1455 errCode = HandleDataStatus(db, logTblName, hashKey, isLock);
1456 if (errCode != DistributedDB::E_OK && errCode != -DistributedDB::E_NOT_FOUND &&
1457 errCode != -DistributedDB::E_WAIT_COMPENSATED_SYNC) {
1458 int ret = SQLiteUtils::RollbackTransaction(db);
1459 if (ret != DistributedDB::E_OK) {
1460 LOGE("rollback failed when lock data:%d, isLock:%d", ret, isLock);
1461 }
1462 return DistributedDB::TransferDBErrno(errCode);
1463 }
1464 int ret = SQLiteUtils::CommitTransaction(db);
1465 if (ret != DistributedDB::E_OK) {
1466 LOGE("commit failed when lock data:%d, isLock:%d", ret, isLock);
1467 }
1468 return errCode == DistributedDB::E_OK ? DistributedDB::TransferDBErrno(ret) :
1469 DistributedDB::TransferDBErrno(errCode);
1470 }
1471
GetDBIdentity(sqlite3 * db,std::string & identity)1472 int GetDBIdentity(sqlite3 *db, std::string &identity)
1473 {
1474 auto filePath = sqlite3_db_filename(db, "main");
1475 if (filePath == nullptr) {
1476 return -E_ERROR;
1477 }
1478 identity = std::string(filePath);
1479 return E_OK;
1480 }
1481
PostHandle(bool isExists,sqlite3 * db)1482 void PostHandle(bool isExists, sqlite3 *db)
1483 {
1484 std::string dbIdentity;
1485 (void)GetDBIdentity(db, dbIdentity);
1486 if (!isExists) { // first create db, clean old time helper
1487 TimeHelperManager::GetInstance()->Restore(dbIdentity);
1488 }
1489 TimeHelperManager::GetInstance()->AddStore(dbIdentity);
1490 RegisterCalcHash(db);
1491 RegisterGetSysTime(db);
1492 RegisterGetLastTime(db);
1493 RegisterGetRawSysTime(db);
1494 RegisterCloudDataChangeObserver(db);
1495 RegisterDataChangeObserver(db);
1496 RegisterCommitAndRollbackHook(db);
1497 (void)sqlite3_set_droptable_handle(db, &ClearTheLogAfterDropTable);
1498 (void)sqlite3_busy_timeout(db, BUSY_TIMEOUT);
1499 std::string recursiveTrigger = "PRAGMA recursive_triggers = ON;";
1500 (void)ExecuteRawSQL(db, recursiveTrigger);
1501 }
1502
GetTableInfos(sqlite3 * db,std::map<std::string,bool> & tableInfos)1503 int GetTableInfos(sqlite3 *db, std::map<std::string, bool> &tableInfos)
1504 {
1505 if (db == nullptr) {
1506 return -E_ERROR;
1507 }
1508 std::string sql = "SELECT name FROM main.sqlite_master WHERE type = 'table'";
1509 sqlite3_stmt *stmt = nullptr;
1510 int errCode = GetStatement(db, sql, stmt);
1511 if (errCode != E_OK) {
1512 LOGE("Prepare get table and primary key statement failed. err=%d", errCode);
1513 return -E_ERROR;
1514 }
1515 while ((errCode = StepWithRetry(stmt)) != SQLITE_DONE) {
1516 if (errCode != SQLITE_ROW) {
1517 ResetStatement(stmt);
1518 return -E_ERROR;
1519 }
1520 std::string tableName;
1521 GetColumnTextValue(stmt, 0, tableName);
1522 if (tableName.empty() || !ParamCheckUtils::CheckRelationalTableName(tableName) ||
1523 tableName.find("sqlite_") == 0 || tableName.find("naturalbase_") == 0) {
1524 continue;
1525 }
1526 tableInfos.insert(std::make_pair(tableName, true));
1527 }
1528 ResetStatement(stmt);
1529 for (auto &tableInfo : tableInfos) {
1530 std::string type = "";
1531 JudgeIfGetRowid(db, tableInfo.first, type, tableInfo.second);
1532 }
1533 return E_OK;
1534 }
1535
CreateTempTrigger(sqlite3 * db)1536 int CreateTempTrigger(sqlite3 *db)
1537 {
1538 std::map<std::string, bool> tableInfos;
1539 int errCode = GetTableInfos(db, tableInfos);
1540 if (errCode != E_OK) {
1541 return errCode;
1542 }
1543 std::vector<std::string> triggerSqls;
1544 errCode = GetTriggerSqls(db, tableInfos, triggerSqls);
1545 if (errCode != E_OK) {
1546 return errCode;
1547 }
1548 for (const auto &sql : triggerSqls) {
1549 errCode = SQLiteUtils::ExecuteRawSQL(db, sql);
1550 if (errCode != E_OK) {
1551 LOGE("Create data change trigger failed %d", errCode);
1552 return errCode;
1553 }
1554 }
1555 return errCode;
1556 }
1557 }
1558
sqlite3_open_relational(const char * filename,sqlite3 ** ppDb)1559 SQLITE_API int sqlite3_open_relational(const char *filename, sqlite3 **ppDb)
1560 {
1561 bool isExists = (access(filename, 0) == 0);
1562 int err = sqlite3_open(filename, ppDb);
1563 if (err != SQLITE_OK) {
1564 return err;
1565 }
1566 PostHandle(isExists, *ppDb);
1567 return err;
1568 }
1569
sqlite3_open16_relational(const void * filename,sqlite3 ** ppDb)1570 SQLITE_API int sqlite3_open16_relational(const void *filename, sqlite3 **ppDb)
1571 {
1572 bool isExists = (access(static_cast<const char *>(filename), 0) == 0);
1573 int err = sqlite3_open16(filename, ppDb);
1574 if (err != SQLITE_OK) { // LCOV_EXCL_BR_LINE
1575 return err;
1576 }
1577 PostHandle(isExists, *ppDb);
1578 return err;
1579 }
1580
sqlite3_open_v2_relational(const char * filename,sqlite3 ** ppDb,int flags,const char * zVfs)1581 SQLITE_API int sqlite3_open_v2_relational(const char *filename, sqlite3 **ppDb, int flags, const char *zVfs)
1582 {
1583 bool isExists = (access(filename, 0) == 0);
1584 int err = sqlite3_open_v2(filename, ppDb, flags, zVfs);
1585 if (err != SQLITE_OK) {
1586 return err;
1587 }
1588 PostHandle(isExists, *ppDb);
1589 return err;
1590 }
1591
RegisterClientObserver(sqlite3 * db,const ClientObserver & clientObserver)1592 DB_API DistributedDB::DBStatus RegisterClientObserver(sqlite3 *db, const ClientObserver &clientObserver)
1593 {
1594 std::string fileName;
1595 if (clientObserver == nullptr || !GetDbFileName(db, fileName)) {
1596 return DistributedDB::INVALID_ARGS;
1597 }
1598
1599 std::string hashFileName;
1600 int errCode = GetHashString(fileName, hashFileName);
1601 if (errCode != DistributedDB::E_OK) {
1602 return DistributedDB::DB_ERROR;
1603 }
1604
1605 std::lock_guard<std::mutex> lock(g_clientObserverMutex);
1606 g_clientObserverMap[hashFileName] = clientObserver;
1607 return DistributedDB::OK;
1608 }
1609
UnRegisterClientObserver(sqlite3 * db)1610 DB_API DistributedDB::DBStatus UnRegisterClientObserver(sqlite3 *db)
1611 {
1612 std::string fileName;
1613 if (!GetDbFileName(db, fileName)) {
1614 return DistributedDB::INVALID_ARGS;
1615 }
1616
1617 std::string hashFileName;
1618 int errCode = GetHashString(fileName, hashFileName);
1619 if (errCode != DistributedDB::E_OK) {
1620 return DistributedDB::DB_ERROR;
1621 }
1622
1623 std::lock_guard<std::mutex> lock(g_clientObserverMutex);
1624 auto it = g_clientObserverMap.find(hashFileName);
1625 if (it != g_clientObserverMap.end()) {
1626 g_clientObserverMap.erase(it);
1627 }
1628 return DistributedDB::OK;
1629 }
1630
RegisterStoreObserver(sqlite3 * db,const std::shared_ptr<StoreObserver> & storeObserver)1631 DB_API DistributedDB::DBStatus RegisterStoreObserver(sqlite3 *db, const std::shared_ptr<StoreObserver> &storeObserver)
1632 {
1633 if (storeObserver == nullptr) {
1634 LOGE("[RegisterStoreObserver] StoreObserver is invalid.");
1635 return DistributedDB::INVALID_ARGS;
1636 }
1637
1638 std::string fileName;
1639 if (!GetDbFileName(db, fileName)) {
1640 LOGE("[RegisterStoreObserver] Get db filename failed.");
1641 return DistributedDB::INVALID_ARGS;
1642 }
1643
1644 std::string hashFileName;
1645 int errCode = GetHashString(fileName, hashFileName);
1646 if (errCode != DistributedDB::E_OK) {
1647 LOGE("[RegisterStoreObserver] Get db filename hash string failed.");
1648 return DistributedDB::DB_ERROR;
1649 }
1650
1651 errCode = CreateTempTrigger(db);
1652 if (errCode != DistributedDB::E_OK) {
1653 LOGE("[RegisterStoreObserver] Create trigger failed.");
1654 return DistributedDB::DB_ERROR;
1655 }
1656
1657 std::lock_guard<std::mutex> lock(g_storeObserverMutex);
1658 if (std::find(g_storeObserverMap[hashFileName].begin(), g_storeObserverMap[hashFileName].end(), storeObserver) !=
1659 g_storeObserverMap[hashFileName].end()) {
1660 LOGE("[RegisterStoreObserver] Duplicate observer.");
1661 return DistributedDB::INVALID_ARGS;
1662 }
1663 g_storeObserverMap[hashFileName].push_back(storeObserver);
1664 return DistributedDB::OK;
1665 }
1666
UnregisterStoreObserver(sqlite3 * db,const std::shared_ptr<StoreObserver> & storeObserver)1667 DB_API DistributedDB::DBStatus UnregisterStoreObserver(sqlite3 *db, const std::shared_ptr<StoreObserver> &storeObserver)
1668 {
1669 if (storeObserver == nullptr) {
1670 LOGE("[UnregisterStoreObserver] StoreObserver is invalid.");
1671 return DistributedDB::INVALID_ARGS;
1672 }
1673
1674 std::string fileName;
1675 if (!GetDbFileName(db, fileName)) {
1676 LOGE("[UnregisterStoreObserver] Get db filename failed.");
1677 return DistributedDB::INVALID_ARGS;
1678 }
1679
1680 std::string hashFileName;
1681 int errCode = GetHashString(fileName, hashFileName);
1682 if (errCode != DistributedDB::E_OK) {
1683 LOGE("[UnregisterStoreObserver] Get db filename hash string failed.");
1684 return DistributedDB::DB_ERROR;
1685 }
1686
1687 std::lock_guard<std::mutex> lock(g_storeObserverMutex);
1688 auto it = g_storeObserverMap.find(hashFileName);
1689 if (it != g_storeObserverMap.end()) {
1690 it->second.remove(storeObserver);
1691 if (it->second.empty()) {
1692 g_storeObserverMap.erase(it);
1693 }
1694 }
1695
1696 return DistributedDB::OK;
1697 }
1698
UnregisterStoreObserver(sqlite3 * db)1699 DB_API DistributedDB::DBStatus UnregisterStoreObserver(sqlite3 *db)
1700 {
1701 std::string fileName;
1702 if (!GetDbFileName(db, fileName)) {
1703 LOGE("[UnregisterAllStoreObserver] StoreObserver is invalid.");
1704 return DistributedDB::INVALID_ARGS;
1705 }
1706
1707 std::string hashFileName;
1708 int errCode = GetHashString(fileName, hashFileName);
1709 if (errCode != DistributedDB::E_OK) {
1710 LOGE("[UnregisterAllStoreObserver] Get db filename hash string failed.");
1711 return DistributedDB::DB_ERROR;
1712 }
1713
1714 std::lock_guard<std::mutex> lock(g_storeObserverMutex);
1715 auto it = g_storeObserverMap.find(hashFileName);
1716 if (it != g_storeObserverMap.end()) {
1717 g_storeObserverMap.erase(it);
1718 }
1719 return DistributedDB::OK;
1720 }
1721
DropLogicDeletedData(sqlite3 * db,const std::string & tableName,uint64_t cursor)1722 DB_API DistributedDB::DBStatus DropLogicDeletedData(sqlite3 *db, const std::string &tableName, uint64_t cursor)
1723 {
1724 std::string fileName;
1725 if (!GetDbFileName(db, fileName)) {
1726 return DistributedDB::INVALID_ARGS;
1727 }
1728 if (tableName.empty()) {
1729 return DistributedDB::INVALID_ARGS;
1730 }
1731 int errCode = SQLiteUtils::BeginTransaction(db, TransactType::IMMEDIATE);
1732 if (errCode != DistributedDB::E_OK) {
1733 LOGE("begin transaction failed before drop logic deleted data. %d", errCode);
1734 return DistributedDB::TransferDBErrno(errCode);
1735 }
1736 errCode = HandleDropLogicDeleteData(db, tableName, cursor);
1737 if (errCode != SQLITE_OK) {
1738 int ret = SQLiteUtils::RollbackTransaction(db);
1739 if (ret != DistributedDB::E_OK) {
1740 LOGE("rollback failed when drop logic deleted data. %d", ret);
1741 }
1742 return DistributedDB::TransferDBErrno(errCode);
1743 }
1744 int ret = SQLiteUtils::CommitTransaction(db);
1745 if (ret != DistributedDB::E_OK) {
1746 LOGE("commit failed when drop logic deleted data. %d", ret);
1747 }
1748 return ret == DistributedDB::E_OK ? DistributedDB::OK : DistributedDB::TransferDBErrno(ret);
1749 }
1750
Lock(const std::string & tableName,const std::vector<std::vector<uint8_t>> & hashKey,sqlite3 * db)1751 DB_API DistributedDB::DBStatus Lock(const std::string &tableName, const std::vector<std::vector<uint8_t>> &hashKey,
1752 sqlite3 *db)
1753 {
1754 return HandleDataLock(tableName, hashKey, db, true);
1755 }
1756
UnLock(const std::string & tableName,const std::vector<std::vector<uint8_t>> & hashKey,sqlite3 * db)1757 DB_API DistributedDB::DBStatus UnLock(const std::string &tableName, const std::vector<std::vector<uint8_t>> &hashKey,
1758 sqlite3 *db)
1759 {
1760 return HandleDataLock(tableName, hashKey, db, false);
1761 }
1762
1763 // hw export the symbols
1764 #ifdef SQLITE_DISTRIBUTE_RELATIONAL
1765 #if defined(__GNUC__)
1766 # define EXPORT_SYMBOLS __attribute__ ((visibility ("default")))
1767 #elif defined(_MSC_VER)
1768 # define EXPORT_SYMBOLS __declspec(dllexport)
1769 #else
1770 # define EXPORT_SYMBOLS
1771 #endif
1772
1773 struct sqlite3_api_routines_relational {
1774 int (*open)(const char *, sqlite3 **);
1775 int (*open16)(const void *, sqlite3 **);
1776 int (*open_v2)(const char *, sqlite3 **, int, const char *);
1777 };
1778
1779 typedef struct sqlite3_api_routines_relational sqlite3_api_routines_relational;
1780 static const sqlite3_api_routines_relational sqlite3HwApis = {
1781 #ifdef SQLITE_DISTRIBUTE_RELATIONAL
1782 sqlite3_open_relational,
1783 sqlite3_open16_relational,
1784 sqlite3_open_v2_relational
1785 #else
1786 0,
1787 0,
1788 0
1789 #endif
1790 };
1791
1792 EXPORT_SYMBOLS const sqlite3_api_routines_relational *sqlite3_export_relational_symbols = &sqlite3HwApis;
1793 #endif
1794