• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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