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
16 #include "sqlite_utils.h"
17
18 #include <climits>
19 #include <cstring>
20 #include <chrono>
21 #include <thread>
22 #include <mutex>
23 #include <map>
24 #include <algorithm>
25
26 #include "sqlite_import.h"
27 #include "securec.h"
28 #include "db_constant.h"
29 #include "db_common.h"
30 #include "db_errno.h"
31 #include "log_print.h"
32 #include "value_object.h"
33 #include "schema_utils.h"
34 #include "schema_constant.h"
35 #include "time_helper.h"
36 #include "platform_specific.h"
37 #include "sqlite_relational_utils.h"
38
39 namespace DistributedDB {
40 namespace {
41 const int BUSY_TIMEOUT_MS = 3000; // 3000ms for sqlite busy timeout.
42 const int USING_STR_LEN = -1;
43 const std::string CIPHER_CONFIG_SQL = "PRAGMA codec_cipher=";
44 const std::string KDF_ITER_CONFIG_SQL = "PRAGMA codec_kdf_iter=";
45 const std::string USER_VERSION_SQL = "PRAGMA user_version;";
46 const std::string WAL_MODE_SQL = "PRAGMA journal_mode=WAL;";
47 const std::string SHA1_ALGO_SQL = "PRAGMA codec_hmac_algo=SHA1;";
48 const std::string SHA256_ALGO_REKEY_SQL = "PRAGMA codec_rekey_hmac_algo=SHA256;";
49
50 const constexpr char *CHECK_TABLE_CREATED = "SELECT EXISTS(SELECT 1 FROM sqlite_master WHERE " \
51 "type='table' AND (tbl_name=? COLLATE NOCASE));";
52 const constexpr char *CHECK_META_DB_TABLE_CREATED = "SELECT EXISTS(SELECT 1 FROM meta.sqlite_master WHERE " \
53 "type='table' AND (tbl_name=? COLLATE NOCASE));";
54 }
55
56 struct ValueParseCache {
57 ValueObject valueParsed;
58 std::vector<uint8_t> valueOriginal;
59 };
60
61 namespace {
IsDeleteRecord(const uint8_t * valueBlob,int valueBlobLen)62 inline bool IsDeleteRecord(const uint8_t *valueBlob, int valueBlobLen)
63 {
64 return (valueBlob == nullptr) || (valueBlobLen <= 0); // In fact, sqlite guarantee valueBlobLen not negative
65 }
66
67 // Use the same cache id as sqlite use for json_extract which is substituted by our json_extract_by_path
68 // A negative cache-id enables sharing of cache between different operation during the same statement
69 constexpr int VALUE_CACHE_ID = -429938;
70
ValueParseCacheFree(ValueParseCache * inCache)71 void ValueParseCacheFree(ValueParseCache *inCache)
72 {
73 if (inCache != nullptr) {
74 delete inCache;
75 }
76 }
77
78 // We don't use cache array since we only cache value column of sqlite table, see sqlite implementation for compare.
ParseValueThenCacheOrGetFromCache(sqlite3_context * ctx,const uint8_t * valueBlob,uint32_t valueBlobLen,uint32_t offset)79 const ValueObject *ParseValueThenCacheOrGetFromCache(sqlite3_context *ctx, const uint8_t *valueBlob,
80 uint32_t valueBlobLen, uint32_t offset)
81 {
82 // Note: All parameter had already been check inside JsonExtractByPath, only called by JsonExtractByPath
83 auto cached = static_cast<ValueParseCache *>(sqlite3_get_auxdata(ctx, VALUE_CACHE_ID));
84 if (cached != nullptr) { // A previous cache exist
85 if (cached->valueOriginal.size() == valueBlobLen) {
86 if (std::memcmp(cached->valueOriginal.data(), valueBlob, valueBlobLen) == 0) {
87 // Cache match
88 return &(cached->valueParsed);
89 }
90 }
91 }
92 // No cache or cache mismatch
93 auto newCache = new (std::nothrow) ValueParseCache;
94 if (newCache == nullptr) {
95 sqlite3_result_error(ctx, "[ParseValueCache] OOM.", USING_STR_LEN);
96 LOGE("[ParseValueCache] OOM.");
97 return nullptr;
98 }
99 int errCode = newCache->valueParsed.Parse(valueBlob, valueBlob + valueBlobLen, offset);
100 if (errCode != E_OK) {
101 sqlite3_result_error(ctx, "[ParseValueCache] Parse fail.", USING_STR_LEN);
102 LOGE("[ParseValueCache] Parse fail, errCode=%d.", errCode);
103 delete newCache;
104 newCache = nullptr;
105 return nullptr;
106 }
107 newCache->valueOriginal.assign(valueBlob, valueBlob + valueBlobLen);
108 sqlite3_set_auxdata(ctx, VALUE_CACHE_ID, newCache, reinterpret_cast<void(*)(void*)>(ValueParseCacheFree));
109 // If sqlite3_set_auxdata fail, it will immediately call ValueParseCacheFree to delete newCache;
110 // Next time sqlite3_set_auxdata will call ValueParseCacheFree to delete newCache of this time;
111 // At the end, newCache will be eventually deleted when call sqlite3_reset or sqlite3_finalize;
112 // Since sqlite3_set_auxdata may fail, we have to call sqlite3_get_auxdata other than return newCache directly.
113 auto cacheInAuxdata = static_cast<ValueParseCache *>(sqlite3_get_auxdata(ctx, VALUE_CACHE_ID));
114 if (cacheInAuxdata == nullptr) {
115 return nullptr;
116 }
117 return &(cacheInAuxdata->valueParsed);
118 }
119 }
120
JsonExtractByPath(sqlite3_context * ctx,int argc,sqlite3_value ** argv)121 void SQLiteUtils::JsonExtractByPath(sqlite3_context *ctx, int argc, sqlite3_value **argv)
122 {
123 if (ctx == nullptr || argc != 3 || argv == nullptr) { // 3 parameters, which are value, path and offset
124 LOGE("[JsonExtract] Invalid parameter, argc=%d.", argc);
125 return;
126 }
127 auto valueBlob = static_cast<const uint8_t *>(sqlite3_value_blob(argv[0]));
128 int valueBlobLen = sqlite3_value_bytes(argv[0]);
129 if (IsDeleteRecord(valueBlob, valueBlobLen)) {
130 // Currently delete records are filtered out of query and create-index sql, so not allowed here.
131 sqlite3_result_error(ctx, "[JsonExtract] Delete record not allowed.", USING_STR_LEN);
132 LOGE("[JsonExtract] Delete record not allowed.");
133 return;
134 }
135 auto path = reinterpret_cast<const char *>(sqlite3_value_text(argv[1]));
136 int offset = sqlite3_value_int(argv[2]); // index 2 is the third parameter
137 if ((path == nullptr) || (offset < 0)) {
138 sqlite3_result_error(ctx, "[JsonExtract] Path nullptr or offset invalid.", USING_STR_LEN);
139 LOGE("[JsonExtract] Path nullptr or offset=%d invalid.", offset);
140 return;
141 }
142 FieldPath outPath;
143 int errCode = SchemaUtils::ParseAndCheckFieldPath(path, outPath);
144 if (errCode != E_OK) {
145 sqlite3_result_error(ctx, "[JsonExtract] Path illegal.", USING_STR_LEN);
146 LOGE("[JsonExtract] Path illegal.");
147 return;
148 }
149 // Parameter Check Done Here
150 const ValueObject *valueObj = ParseValueThenCacheOrGetFromCache(ctx, valueBlob, static_cast<uint32_t>(valueBlobLen),
151 static_cast<uint32_t>(offset));
152 if (valueObj == nullptr) {
153 return; // Necessary had been printed in ParseValueThenCacheOrGetFromCache
154 }
155 JsonExtractInnerFunc(ctx, *valueObj, outPath);
156 }
157
158 namespace {
IsExtractableType(FieldType inType)159 inline bool IsExtractableType(FieldType inType)
160 {
161 return (inType != FieldType::LEAF_FIELD_NULL && inType != FieldType::LEAF_FIELD_ARRAY &&
162 inType != FieldType::LEAF_FIELD_OBJECT && inType != FieldType::INTERNAL_FIELD_OBJECT);
163 }
164 }
165
JsonExtractInnerFunc(sqlite3_context * ctx,const ValueObject & inValue,const FieldPath & inPath)166 void SQLiteUtils::JsonExtractInnerFunc(sqlite3_context *ctx, const ValueObject &inValue, const FieldPath &inPath)
167 {
168 FieldType outType = FieldType::LEAF_FIELD_NULL; // Default type null for invalid-path(path not exist)
169 int errCode = inValue.GetFieldTypeByFieldPath(inPath, outType);
170 if (errCode != E_OK && errCode != -E_INVALID_PATH) {
171 sqlite3_result_error(ctx, "[JsonExtract] GetFieldType fail.", USING_STR_LEN);
172 LOGE("[JsonExtract] GetFieldType fail, errCode=%d.", errCode);
173 return;
174 }
175 FieldValue outValue;
176 if (IsExtractableType(outType)) {
177 errCode = inValue.GetFieldValueByFieldPath(inPath, outValue);
178 if (errCode != E_OK) {
179 sqlite3_result_error(ctx, "[JsonExtract] GetFieldValue fail.", USING_STR_LEN);
180 LOGE("[JsonExtract] GetFieldValue fail, errCode=%d.", errCode);
181 return;
182 }
183 }
184 // FieldType null, array, object do not have value, all these FieldValue will be regarded as null in JsonReturn.
185 ExtractReturn(ctx, outType, outValue);
186 }
187
188 // NOTE!!! This function is performance sensitive !!! Carefully not to allocate memory often!!!
FlatBufferExtractByPath(sqlite3_context * ctx,int argc,sqlite3_value ** argv)189 void SQLiteUtils::FlatBufferExtractByPath(sqlite3_context *ctx, int argc, sqlite3_value **argv)
190 {
191 if (ctx == nullptr || argc != 3 || argv == nullptr) { // 3 parameters, which are value, path and offset
192 LOGE("[FlatBufferExtract] Invalid parameter, argc=%d.", argc);
193 return;
194 }
195 auto schema = static_cast<SchemaObject *>(sqlite3_user_data(ctx));
196 if (schema == nullptr || !schema->IsSchemaValid() ||
197 (schema->GetSchemaType() != SchemaType::FLATBUFFER)) { // LCOV_EXCL_BR_LINE
198 sqlite3_result_error(ctx, "[FlatBufferExtract] No SchemaObject or invalid.", USING_STR_LEN);
199 LOGE("[FlatBufferExtract] No SchemaObject or invalid.");
200 return;
201 }
202 // Get information from argv
203 auto valueBlob = static_cast<const uint8_t *>(sqlite3_value_blob(argv[0]));
204 int valueBlobLen = sqlite3_value_bytes(argv[0]);
205 if (IsDeleteRecord(valueBlob, valueBlobLen)) { // LCOV_EXCL_BR_LINE
206 // Currently delete records are filtered out of query and create-index sql, so not allowed here.
207 sqlite3_result_error(ctx, "[FlatBufferExtract] Delete record not allowed.", USING_STR_LEN);
208 LOGE("[FlatBufferExtract] Delete record not allowed.");
209 return;
210 }
211 auto path = reinterpret_cast<const char *>(sqlite3_value_text(argv[1]));
212 int offset = sqlite3_value_int(argv[2]); // index 2 is the third parameter
213 if ((path == nullptr) || (offset < 0) ||
214 (static_cast<uint32_t>(offset) != schema->GetSkipSize())) { // LCOV_EXCL_BR_LINE
215 sqlite3_result_error(ctx, "[FlatBufferExtract] Path null or offset invalid.", USING_STR_LEN);
216 LOGE("[FlatBufferExtract] Path null or offset=%d(skipsize=%u) invalid.", offset, schema->GetSkipSize());
217 return;
218 }
219 FlatBufferExtractInnerFunc(ctx, *schema, RawValue { valueBlob, valueBlobLen }, path);
220 }
221
222 namespace {
223 constexpr uint32_t FLATBUFFER_MAX_CACHE_SIZE = 102400; // 100 KBytes
224
FlatBufferCacheFree(std::vector<uint8_t> * inCache)225 void FlatBufferCacheFree(std::vector<uint8_t> *inCache)
226 {
227 if (inCache != nullptr) {
228 delete inCache;
229 }
230 }
231 }
232
FlatBufferExtractInnerFunc(sqlite3_context * ctx,const SchemaObject & schema,const RawValue & inValue,RawString inPath)233 void SQLiteUtils::FlatBufferExtractInnerFunc(sqlite3_context *ctx, const SchemaObject &schema, const RawValue &inValue,
234 RawString inPath)
235 {
236 // All parameter had already been check inside FlatBufferExtractByPath, only called by FlatBufferExtractByPath
237 if (schema.GetSkipSize() % SchemaConstant::SECURE_BYTE_ALIGN == 0) { // LCOV_EXCL_BR_LINE
238 TypeValue outExtract;
239 int errCode = schema.ExtractValue(ValueSource::FROM_DBFILE, inPath, inValue, outExtract, nullptr);
240 if (errCode != E_OK) { // LCOV_EXCL_BR_LINE
241 sqlite3_result_error(ctx, "[FlatBufferExtract] ExtractValue fail.", USING_STR_LEN);
242 LOGE("[FlatBufferExtract] ExtractValue fail, errCode=%d.", errCode);
243 return;
244 }
245 ExtractReturn(ctx, outExtract.first, outExtract.second);
246 return;
247 }
248 // Not byte-align secure, we have to make a cache for copy. Check whether cache had already exist.
249 auto cached = static_cast<std::vector<uint8_t> *>(sqlite3_get_auxdata(ctx, VALUE_CACHE_ID)); // Share the same id
250 if (cached == nullptr) { // LCOV_EXCL_BR_LINE
251 // Make the cache
252 auto newCache = new (std::nothrow) std::vector<uint8_t>;
253 if (newCache == nullptr) {
254 sqlite3_result_error(ctx, "[FlatBufferExtract] OOM.", USING_STR_LEN);
255 LOGE("[FlatBufferExtract] OOM.");
256 return;
257 }
258 newCache->resize(FLATBUFFER_MAX_CACHE_SIZE);
259 sqlite3_set_auxdata(ctx, VALUE_CACHE_ID, newCache, reinterpret_cast<void(*)(void*)>(FlatBufferCacheFree));
260 // If sqlite3_set_auxdata fail, it will immediately call FlatBufferCacheFree to delete newCache;
261 // Next time sqlite3_set_auxdata will call FlatBufferCacheFree to delete newCache of this time;
262 // At the end, newCache will be eventually deleted when call sqlite3_reset or sqlite3_finalize;
263 // Since sqlite3_set_auxdata may fail, we have to call sqlite3_get_auxdata other than return newCache directly.
264 // See sqlite.org for more information.
265 cached = static_cast<std::vector<uint8_t> *>(sqlite3_get_auxdata(ctx, VALUE_CACHE_ID));
266 }
267 if (cached == nullptr) { // LCOV_EXCL_BR_LINE
268 LOGW("[FlatBufferExtract] Something wrong with Auxdata, but it is no matter without cache.");
269 }
270 TypeValue outExtract;
271 int errCode = schema.ExtractValue(ValueSource::FROM_DBFILE, inPath, inValue, outExtract, cached);
272 if (errCode != E_OK) { // LCOV_EXCL_BR_LINE
273 sqlite3_result_error(ctx, "[FlatBufferExtract] ExtractValue fail.", USING_STR_LEN);
274 LOGE("[FlatBufferExtract] ExtractValue fail, errCode=%d.", errCode);
275 return;
276 }
277 ExtractReturn(ctx, outExtract.first, outExtract.second);
278 }
279
ExtractReturn(sqlite3_context * ctx,FieldType type,const FieldValue & value)280 void SQLiteUtils::ExtractReturn(sqlite3_context *ctx, FieldType type, const FieldValue &value)
281 {
282 if (ctx == nullptr) {
283 return;
284 }
285 switch (type) {
286 case FieldType::LEAF_FIELD_BOOL:
287 sqlite3_result_int(ctx, (value.boolValue ? 1 : 0));
288 break;
289 case FieldType::LEAF_FIELD_INTEGER:
290 sqlite3_result_int(ctx, value.integerValue);
291 break;
292 case FieldType::LEAF_FIELD_LONG:
293 sqlite3_result_int64(ctx, value.longValue);
294 break;
295 case FieldType::LEAF_FIELD_DOUBLE:
296 sqlite3_result_double(ctx, value.doubleValue);
297 break;
298 case FieldType::LEAF_FIELD_STRING:
299 // The SQLITE_TRANSIENT value means that the content will likely change in the near future and
300 // that SQLite should make its own private copy of the content before returning.
301 sqlite3_result_text(ctx, value.stringValue.c_str(), -1, SQLITE_TRANSIENT); // -1 mean use the string length
302 break;
303 default:
304 // All other type regard as null
305 sqlite3_result_null(ctx);
306 }
307 return;
308 }
309
CalcHashFunc(sqlite3_context * ctx,sqlite3_value ** argv)310 static void CalcHashFunc(sqlite3_context *ctx, sqlite3_value **argv)
311 {
312 auto keyBlob = static_cast<const uint8_t *>(sqlite3_value_blob(argv[0]));
313 if (keyBlob == nullptr) {
314 sqlite3_result_error(ctx, "Parameters is invalid.", USING_STR_LEN);
315 LOGE("Parameters is invalid.");
316 return;
317 }
318 int blobLen = sqlite3_value_bytes(argv[0]);
319 std::vector<uint8_t> value(keyBlob, keyBlob + blobLen);
320 std::vector<uint8_t> hashValue;
321 int errCode = DBCommon::CalcValueHash(value, hashValue);
322 if (errCode != E_OK) {
323 sqlite3_result_error(ctx, "Get hash value error.", USING_STR_LEN);
324 LOGE("Get hash value error.");
325 return;
326 }
327 sqlite3_result_blob(ctx, hashValue.data(), hashValue.size(), SQLITE_TRANSIENT);
328 }
329
CalcHashKey(sqlite3_context * ctx,int argc,sqlite3_value ** argv)330 void SQLiteUtils::CalcHashKey(sqlite3_context *ctx, int argc, sqlite3_value **argv)
331 {
332 // 1 means that the function only needs one parameter, namely key
333 if (ctx == nullptr || argc != 1 || argv == nullptr) {
334 LOGE("Parameter does not meet restrictions.");
335 return;
336 }
337 CalcHashFunc(ctx, argv);
338 }
339
CalcHash(sqlite3_context * ctx,int argc,sqlite3_value ** argv)340 void SQLiteUtils::CalcHash(sqlite3_context *ctx, int argc, sqlite3_value **argv)
341 {
342 if (ctx == nullptr || argc != 2 || argv == nullptr) { // 2 is params count
343 LOGE("Parameter does not meet restrictions.");
344 return;
345 }
346 CalcHashFunc(ctx, argv);
347 }
348
349
GetDbSize(const std::string & dir,const std::string & dbName,uint64_t & size)350 int SQLiteUtils::GetDbSize(const std::string &dir, const std::string &dbName, uint64_t &size)
351 {
352 std::string dataDir = dir + "/" + dbName + DBConstant::DB_EXTENSION;
353 uint64_t localDbSize = 0;
354 int errCode = OS::CalFileSize(dataDir, localDbSize);
355 if (errCode != E_OK) {
356 LOGD("Failed to get the db file size, errCode:%d", errCode);
357 return errCode;
358 }
359
360 std::string shmFileName = dataDir + "-shm";
361 uint64_t localshmFileSize = 0;
362 errCode = OS::CalFileSize(shmFileName, localshmFileSize);
363 if (errCode != E_OK) {
364 localshmFileSize = 0;
365 }
366
367 std::string walFileName = dataDir + "-wal";
368 uint64_t localWalFileSize = 0;
369 errCode = OS::CalFileSize(walFileName, localWalFileSize);
370 if (errCode != E_OK) {
371 localWalFileSize = 0;
372 }
373
374 // 64-bit system is Suffice. Computer storage is less than uint64_t max
375 size += (localDbSize + localshmFileSize + localWalFileSize);
376 return E_OK;
377 }
378
SetDataBaseProperty(sqlite3 * db,const OpenDbProperties & properties,bool setWal,const std::vector<std::string> & sqls)379 int SQLiteUtils::SetDataBaseProperty(sqlite3 *db, const OpenDbProperties &properties, bool setWal,
380 const std::vector<std::string> &sqls)
381 {
382 // Set the default busy handler to retry automatically before returning SQLITE_BUSY.
383 int errCode = SetBusyTimeout(db, BUSY_TIMEOUT_MS);
384 if (errCode != E_OK) {
385 return errCode;
386 }
387 if (!properties.isMemDb) {
388 errCode = SQLiteUtils::SetKey(db, properties.cipherType, properties.passwd, setWal,
389 properties.iterTimes);
390 if (errCode != E_OK) {
391 LOGD("SQLiteUtils::SetKey fail!!![%d]", errCode);
392 return errCode;
393 }
394 }
395
396 for (const auto &sql : sqls) {
397 errCode = SQLiteUtils::ExecuteRawSQL(db, sql);
398 if (errCode != E_OK) {
399 LOGE("[SQLite] execute sql failed: %d", errCode);
400 return errCode;
401 }
402 }
403 // Create table if not exist according the sqls.
404 if (properties.createIfNecessary) {
405 for (const auto &sql : properties.sqls) {
406 errCode = SQLiteUtils::ExecuteRawSQL(db, sql);
407 if (errCode != E_OK) {
408 LOGE("[SQLite] execute preset sqls failed");
409 return errCode;
410 }
411 }
412 }
413 return E_OK;
414 }
415
416 #ifndef OMIT_ENCRYPT
SetCipherSettings(sqlite3 * db,CipherType type,uint32_t iterTimes)417 int SQLiteUtils::SetCipherSettings(sqlite3 *db, CipherType type, uint32_t iterTimes)
418 {
419 if (db == nullptr) {
420 return -E_INVALID_DB;
421 }
422 std::string cipherName = GetCipherName(type);
423 if (cipherName.empty()) {
424 return -E_INVALID_ARGS;
425 }
426 std::string cipherConfig = CIPHER_CONFIG_SQL + cipherName + ";";
427 int errCode = SQLiteUtils::ExecuteRawSQL(db, cipherConfig);
428 if (errCode != E_OK) {
429 LOGE("[SQLiteUtils][SetCipherSettings] config cipher failed:%d", errCode);
430 return errCode;
431 }
432 errCode = SQLiteUtils::ExecuteRawSQL(db, KDF_ITER_CONFIG_SQL + std::to_string(iterTimes));
433 if (errCode != E_OK) {
434 LOGE("[SQLiteUtils][SetCipherSettings] config iter failed:%d", errCode);
435 }
436 return errCode;
437 }
438
GetCipherName(CipherType type)439 std::string SQLiteUtils::GetCipherName(CipherType type)
440 {
441 if (type == CipherType::AES_256_GCM || type == CipherType::DEFAULT) {
442 return "'aes-256-gcm'";
443 }
444 return "";
445 }
446 #endif
447
DropTriggerByName(sqlite3 * db,const std::string & name)448 int SQLiteUtils::DropTriggerByName(sqlite3 *db, const std::string &name)
449 {
450 const std::string dropTriggerSql = "DROP TRIGGER " + name + ";";
451 int errCode = SQLiteUtils::ExecuteRawSQL(db, dropTriggerSql);
452 if (errCode != E_OK) {
453 LOGE("Remove trigger failed. %d", errCode);
454 }
455 return errCode;
456 }
457
ExpandedSql(sqlite3_stmt * stmt,std::string & basicString)458 int SQLiteUtils::ExpandedSql(sqlite3_stmt *stmt, std::string &basicString)
459 {
460 if (stmt == nullptr) {
461 return -E_INVALID_ARGS;
462 }
463 char *eSql = sqlite3_expanded_sql(stmt);
464 if (eSql == nullptr) {
465 LOGE("expand statement to sql failed.");
466 return -E_INVALID_DATA;
467 }
468 basicString = std::string(eSql);
469 sqlite3_free(eSql);
470 return E_OK;
471 }
472
ExecuteCheckPoint(sqlite3 * db)473 void SQLiteUtils::ExecuteCheckPoint(sqlite3 *db)
474 {
475 if (db == nullptr) {
476 return;
477 }
478
479 int chkResult = sqlite3_wal_checkpoint_v2(db, nullptr, SQLITE_CHECKPOINT_TRUNCATE, nullptr, nullptr);
480 LOGI("SQLite checkpoint result:%d", chkResult);
481 }
482
CheckTableEmpty(sqlite3 * db,const std::string & tableName,bool & isEmpty)483 int SQLiteUtils::CheckTableEmpty(sqlite3 *db, const std::string &tableName, bool &isEmpty)
484 {
485 if (db == nullptr) {
486 return -E_INVALID_ARGS;
487 }
488
489 std::string cntSql = "SELECT min(rowid) FROM '" + tableName + "';";
490 sqlite3_stmt *stmt = nullptr;
491 int errCode = SQLiteUtils::GetStatement(db, cntSql, stmt);
492 if (errCode != E_OK) {
493 return errCode;
494 }
495
496 errCode = SQLiteUtils::StepWithRetry(stmt, false);
497 if (errCode == SQLiteUtils::MapSQLiteErrno(SQLITE_ROW)) {
498 isEmpty = (sqlite3_column_type(stmt, 0) == SQLITE_NULL);
499 errCode = E_OK;
500 }
501
502 SQLiteUtils::ResetStatement(stmt, true, errCode);
503 return SQLiteUtils::MapSQLiteErrno(errCode);
504 }
505
SetPersistWalMode(sqlite3 * db)506 int SQLiteUtils::SetPersistWalMode(sqlite3 *db)
507 {
508 if (db == nullptr) {
509 return -E_INVALID_ARGS;
510 }
511 int opCode = 1;
512 int errCode = sqlite3_file_control(db, "main", SQLITE_FCNTL_PERSIST_WAL, &opCode);
513 if (errCode != SQLITE_OK) {
514 LOGE("Set persist wal mode failed. %d", errCode);
515 }
516 return SQLiteUtils::MapSQLiteErrno(errCode);
517 }
518
GetLastRowId(sqlite3 * db)519 int64_t SQLiteUtils::GetLastRowId(sqlite3 *db)
520 {
521 if (db == nullptr) {
522 return -1;
523 }
524 return sqlite3_last_insert_rowid(db);
525 }
526
GetLastErrorMsg()527 std::string SQLiteUtils::GetLastErrorMsg()
528 {
529 std::lock_guard<std::mutex> autoLock(logMutex_);
530 return lastErrorMsg_;
531 }
532
SetAuthorizer(sqlite3 * db,int (* xAuth)(void *,int,const char *,const char *,const char *,const char *))533 int SQLiteUtils::SetAuthorizer(sqlite3 *db,
534 int (*xAuth)(void*, int, const char*, const char*, const char*, const char*))
535 {
536 return SQLiteUtils::MapSQLiteErrno(sqlite3_set_authorizer(db, xAuth, nullptr));
537 }
538
GetSelectCols(sqlite3_stmt * stmt,std::vector<std::string> & colNames)539 void SQLiteUtils::GetSelectCols(sqlite3_stmt *stmt, std::vector<std::string> &colNames)
540 {
541 colNames.clear();
542 for (int i = 0; i < sqlite3_column_count(stmt); ++i) {
543 const char *name = sqlite3_column_name(stmt, i);
544 colNames.emplace_back(name == nullptr ? std::string() : std::string(name));
545 }
546 }
547
SetKeyInner(sqlite3 * db,CipherType type,const CipherPassword & passwd,uint32_t iterTimes)548 int SQLiteUtils::SetKeyInner(sqlite3 *db, CipherType type, const CipherPassword &passwd, uint32_t iterTimes)
549 {
550 #ifndef OMIT_ENCRYPT
551 int errCode = sqlite3_key(db, static_cast<const void *>(passwd.GetData()), static_cast<int>(passwd.GetSize()));
552 if (errCode != SQLITE_OK) {
553 LOGE("[SQLiteUtils][SetKeyInner] config key failed:(%d)", errCode);
554 return SQLiteUtils::MapSQLiteErrno(errCode);
555 }
556
557 errCode = SQLiteUtils::SetCipherSettings(db, type, iterTimes);
558 if (errCode != E_OK) {
559 LOGE("[SQLiteUtils][SetKeyInner] set cipher settings failed:%d", errCode);
560 }
561 return errCode;
562 #else
563 return -E_NOT_SUPPORT;
564 #endif
565 }
566
BindDataValueByType(sqlite3_stmt * statement,const std::optional<DataValue> & data,int cid)567 int SQLiteUtils::BindDataValueByType(sqlite3_stmt *statement, const std::optional<DataValue> &data, int cid)
568 {
569 int errCode = E_OK;
570 StorageType type = data.value_or(DataValue()).GetType();
571 switch (type) {
572 case StorageType::STORAGE_TYPE_INTEGER: {
573 int64_t intData = 0;
574 (void)data.value().GetInt64(intData);
575 errCode = SQLiteUtils::MapSQLiteErrno(sqlite3_bind_int64(statement, cid, intData));
576 break;
577 }
578
579 case StorageType::STORAGE_TYPE_REAL: {
580 double doubleData = 0;
581 (void)data.value().GetDouble(doubleData);
582 errCode = SQLiteUtils::MapSQLiteErrno(sqlite3_bind_double(statement, cid, doubleData));
583 break;
584 }
585
586 case StorageType::STORAGE_TYPE_TEXT: {
587 std::string strData;
588 (void)data.value().GetText(strData);
589 errCode = SQLiteUtils::BindTextToStatement(statement, cid, strData);
590 break;
591 }
592
593 case StorageType::STORAGE_TYPE_BLOB: {
594 Blob blob;
595 (void)data.value().GetBlob(blob);
596 std::vector<uint8_t> blobData(blob.GetData(), blob.GetData() + blob.GetSize());
597 errCode = SQLiteUtils::BindBlobToStatement(statement, cid, blobData, true);
598 break;
599 }
600
601 case StorageType::STORAGE_TYPE_NULL: {
602 errCode = SQLiteUtils::MapSQLiteErrno(sqlite3_bind_null(statement, cid));
603 break;
604 }
605
606 default:
607 break;
608 }
609 return errCode;
610 }
611
UpdateCipherShaAlgo(sqlite3 * db,bool setWal,CipherType type,const CipherPassword & passwd,uint32_t iterTimes)612 int SQLiteUtils::UpdateCipherShaAlgo(sqlite3 *db, bool setWal, CipherType type, const CipherPassword &passwd,
613 uint32_t iterTimes)
614 {
615 int errCode = SetKeyInner(db, type, passwd, iterTimes);
616 if (errCode != E_OK) {
617 return errCode;
618 }
619 // set sha1 algo for old version
620 errCode = SQLiteUtils::ExecuteRawSQL(db, SHA1_ALGO_SQL);
621 if (errCode != E_OK) {
622 LOGE("[SQLiteUtils][UpdateCipherShaAlgo] set sha algo failed:%d", errCode);
623 return errCode;
624 }
625 // try to get user version
626 errCode = SQLiteUtils::ExecuteRawSQL(db, USER_VERSION_SQL);
627 if (errCode != E_OK) {
628 LOGE("[SQLiteUtils][UpdateCipherShaAlgo] verify version failed:%d", errCode);
629 if (errno == EKEYREVOKED) {
630 return -E_EKEYREVOKED;
631 }
632 return errCode;
633 }
634 // try to update rekey sha algo by rekey operation
635 errCode = SQLiteUtils::ExecuteRawSQL(db, SHA256_ALGO_REKEY_SQL);
636 if (errCode != E_OK) {
637 LOGE("[SQLiteUtils][UpdateCipherShaAlgo] set rekey sha algo failed:%d", errCode);
638 return errCode;
639 }
640 if (setWal) {
641 errCode = SQLiteUtils::ExecuteRawSQL(db, WAL_MODE_SQL);
642 if (errCode != E_OK) {
643 LOGE("[SQLite][UpdateCipherShaAlgo] execute wal sql failed: %d", errCode);
644 return errCode;
645 }
646 }
647 return Rekey(db, passwd);
648 }
649
CheckTableExists(sqlite3 * db,const std::string & tableName,bool & isCreated,bool isCheckMeta)650 int SQLiteUtils::CheckTableExists(sqlite3 *db, const std::string &tableName, bool &isCreated, bool isCheckMeta)
651 {
652 if (db == nullptr) {
653 return -1;
654 }
655
656 sqlite3_stmt *stmt = nullptr;
657 int errCode = SQLiteUtils::GetStatement(db, isCheckMeta ? CHECK_META_DB_TABLE_CREATED : CHECK_TABLE_CREATED, stmt);
658 if (errCode != SQLiteUtils::MapSQLiteErrno(SQLITE_OK)) {
659 LOGE("Get check table statement failed. err=%d", errCode);
660 return errCode;
661 }
662
663 errCode = SQLiteUtils::BindTextToStatement(stmt, 1, tableName);
664 if (errCode != SQLiteUtils::MapSQLiteErrno(SQLITE_OK)) {
665 LOGE("Bind table name to statement failed. err=%d", errCode);
666 goto END;
667 }
668
669 errCode = SQLiteUtils::StepWithRetry(stmt);
670 if (errCode != SQLiteUtils::MapSQLiteErrno(SQLITE_ROW)) {
671 LOGE("Check table exists failed. err=%d", errCode); // should always return a row data
672 goto END;
673 }
674 errCode = E_OK;
675 isCreated = (sqlite3_column_int(stmt, 0) == 1);
676 END:
677 SQLiteUtils::ResetStatement(stmt, true, errCode);
678 return errCode;
679 }
680
StepNext(sqlite3_stmt * stmt,bool isMemDb)681 int SQLiteUtils::StepNext(sqlite3_stmt *stmt, bool isMemDb)
682 {
683 if (stmt == nullptr) {
684 return -E_INVALID_ARGS;
685 }
686 int errCode = SQLiteUtils::StepWithRetry(stmt, isMemDb);
687 if (errCode == SQLiteUtils::MapSQLiteErrno(SQLITE_DONE)) {
688 errCode = -E_FINISHED;
689 } else if (errCode == SQLiteUtils::MapSQLiteErrno(SQLITE_ROW)) {
690 errCode = E_OK;
691 }
692 return errCode;
693 }
694
GetCountBySql(sqlite3 * db,const std::string & sql,int & count)695 int SQLiteUtils::GetCountBySql(sqlite3 *db, const std::string &sql, int &count)
696 {
697 sqlite3_stmt *stmt = nullptr;
698 int errCode = SQLiteUtils::GetStatement(db, sql, stmt);
699 if (errCode != E_OK) {
700 LOGE("[SQLiteUtils][GetCountBySql] Get stmt failed when get local data count: %d", errCode);
701 return errCode;
702 }
703 errCode = SQLiteUtils::StepWithRetry(stmt, false);
704 if (errCode == SQLiteUtils::MapSQLiteErrno(SQLITE_ROW)) {
705 count = static_cast<int>(sqlite3_column_int(stmt, 0));
706 errCode = E_OK;
707 } else {
708 LOGE("[SQLiteUtils][GetCountBySql] Query local data count failed: %d", errCode);
709 }
710 int ret = E_OK;
711 SQLiteUtils::ResetStatement(stmt, true, ret);
712 if (ret != E_OK) {
713 LOGE("[SQLiteUtils][GetCountBySql] Reset stmt failed when get local data count: %d", ret);
714 }
715 return errCode != E_OK ? errCode : ret;
716 }
717
IsStmtReadOnly(sqlite3_stmt * statement)718 bool SQLiteUtils::IsStmtReadOnly(sqlite3_stmt *statement)
719 {
720 if (statement == nullptr) {
721 return false;
722 }
723 int isReadOnly = sqlite3_stmt_readonly(statement);
724 return static_cast<bool>(isReadOnly);
725 }
726 } // namespace DistributedDB
727