1 /*
2 * Copyright (c) 2025 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 "db_common.h"
19 #include "platform_specific.h"
20
21 namespace DistributedDB {
22 namespace {
23 const int BUSY_SLEEP_TIME = 50; // sleep for 50us
24 const int NO_SIZE_LIMIT = -1;
25 const int MAX_STEP_TIMES = 8000;
26 const std::string BEGIN_SQL = "BEGIN TRANSACTION";
27 const std::string BEGIN_IMMEDIATE_SQL = "BEGIN IMMEDIATE TRANSACTION";
28 const std::string COMMIT_SQL = "COMMIT TRANSACTION";
29 const std::string ROLLBACK_SQL = "ROLLBACK TRANSACTION";
30 const int MAX_BLOB_READ_SIZE = 64 * 1024 * 1024; // 64M limit
31 const int MAX_TEXT_READ_SIZE = 5 * 1024 * 1024; // 5M limit
32
33 const constexpr char *CHECK_TABLE_CREATED = "SELECT EXISTS(SELECT 1 FROM sqlite_master WHERE " \
34 "type='table' AND (tbl_name=? COLLATE NOCASE));";
35 const constexpr char *CHECK_META_DB_TABLE_CREATED = "SELECT EXISTS(SELECT 1 FROM meta.sqlite_master WHERE " \
36 "type='table' AND (tbl_name=? COLLATE NOCASE));";
37 }
38
39 namespace TriggerMode {
40 const std::map<TriggerModeEnum, std::string> TRIGGER_MODE_MAP = {
41 {TriggerModeEnum::NONE, ""},
42 {TriggerModeEnum::INSERT, "INSERT"},
43 {TriggerModeEnum::UPDATE, "UPDATE"},
44 {TriggerModeEnum::DELETE, "DELETE"},
45 };
46
GetTriggerModeString(TriggerModeEnum mode)47 std::string GetTriggerModeString(TriggerModeEnum mode)
48 {
49 auto it = TRIGGER_MODE_MAP.find(mode);
50 return (it == TRIGGER_MODE_MAP.end()) ? "" : it->second;
51 }
52 }
53
StepWithRetry(sqlite3_stmt * statement,bool isMemDb)54 int SQLiteUtils::StepWithRetry(sqlite3_stmt *statement, bool isMemDb)
55 {
56 if (statement == nullptr) {
57 return -E_INVALID_ARGS;
58 }
59
60 int errCode = E_OK;
61 int retryCount = 0;
62 do {
63 errCode = sqlite3_step(statement);
64 if ((errCode == SQLITE_LOCKED) && isMemDb) {
65 std::this_thread::sleep_for(std::chrono::microseconds(BUSY_SLEEP_TIME));
66 retryCount++;
67 } else {
68 break;
69 }
70 } while (retryCount <= MAX_STEP_TIMES);
71
72 if (errCode != SQLITE_DONE && errCode != SQLITE_ROW) {
73 LOGE("[SQLiteUtils] Step error:%d, sys:%d", errCode, errno);
74 }
75
76 return SQLiteUtils::MapSQLiteErrno(errCode);
77 }
78
BeginTransaction(sqlite3 * db,TransactType type)79 int SQLiteUtils::BeginTransaction(sqlite3 *db, TransactType type)
80 {
81 if (type == TransactType::IMMEDIATE) {
82 return ExecuteRawSQL(db, BEGIN_IMMEDIATE_SQL, true);
83 }
84
85 return ExecuteRawSQL(db, BEGIN_SQL, true);
86 }
87
CommitTransaction(sqlite3 * db)88 int SQLiteUtils::CommitTransaction(sqlite3 *db)
89 {
90 return ExecuteRawSQL(db, COMMIT_SQL, true);
91 }
92
RollbackTransaction(sqlite3 * db)93 int SQLiteUtils::RollbackTransaction(sqlite3 *db)
94 {
95 return ExecuteRawSQL(db, ROLLBACK_SQL, true);
96 }
97
ExecuteRawSQL(sqlite3 * db,const std::string & sql,bool ignoreResetFail)98 int SQLiteUtils::ExecuteRawSQL(sqlite3 *db, const std::string &sql, bool ignoreResetFail)
99 {
100 if (db == nullptr) {
101 return -E_INVALID_DB;
102 }
103
104 sqlite3_stmt *stmt = nullptr;
105 int errCode = SQLiteUtils::GetStatement(db, sql, stmt);
106 if (errCode != SQLiteUtils::MapSQLiteErrno(SQLITE_OK)) {
107 LOGE("[SQLiteUtils][ExecuteSQL] prepare statement failed(%d), sys(%d)", errCode, errno);
108 return errCode;
109 }
110
111 do {
112 errCode = SQLiteUtils::StepWithRetry(stmt);
113 if (errCode == SQLiteUtils::MapSQLiteErrno(SQLITE_DONE)) {
114 errCode = E_OK;
115 break;
116 } else if (errCode != SQLiteUtils::MapSQLiteErrno(SQLITE_ROW)) {
117 LOGE("[SQLiteUtils][ExecuteSQL] execute statement failed(%d), sys(%d)", errCode, errno);
118 break;
119 }
120 } while (errCode == SQLiteUtils::MapSQLiteErrno(SQLITE_ROW));
121
122 int ret = E_OK;
123 SQLiteUtils::ResetStatement(stmt, true, ret);
124 if (!ignoreResetFail && ret != E_OK) {
125 return errCode != E_OK ? errCode : ret;
126 }
127 return errCode;
128 }
129
MapSQLiteErrno(int errCode)130 int SQLiteUtils::MapSQLiteErrno(int errCode)
131 {
132 switch (errCode) {
133 case SQLITE_OK:
134 return E_OK;
135 case SQLITE_IOERR:
136 if (errno == EKEYREVOKED) {
137 return -E_EKEYREVOKED;
138 }
139 break;
140 case SQLITE_CORRUPT:
141 case SQLITE_NOTADB:
142 return -E_INVALID_PASSWD_OR_CORRUPTED_DB;
143 case SQLITE_LOCKED:
144 case SQLITE_BUSY:
145 return -E_BUSY;
146 case SQLITE_ERROR:
147 if (errno == EKEYREVOKED) {
148 return -E_EKEYREVOKED;
149 }
150 break;
151 case SQLITE_AUTH:
152 return -E_DENIED_SQL;
153 case SQLITE_CONSTRAINT:
154 return -E_CONSTRAINT;
155 case SQLITE_CANTOPEN:
156 return -E_SQLITE_CANT_OPEN;
157 default:
158 break;
159 }
160 return -errCode;
161 }
162
GetStatement(sqlite3 * db,const std::string & sql,sqlite3_stmt * & statement)163 int SQLiteUtils::GetStatement(sqlite3 *db, const std::string &sql, sqlite3_stmt *&statement)
164 {
165 if (db == nullptr) {
166 LOGE("Invalid db for statement");
167 return -E_INVALID_DB;
168 }
169 // Prepare the new statement only when the input parameter is not null
170 if (statement != nullptr) {
171 return E_OK;
172 }
173 int errCode = sqlite3_prepare_v2(db, sql.c_str(), NO_SIZE_LIMIT, &statement, nullptr);
174 if (errCode != SQLITE_OK) {
175 LOGE("Prepare SQLite statement failed:%d, sys:%d", errCode, errno);
176 errCode = SQLiteUtils::MapSQLiteErrno(errCode);
177 SQLiteUtils::ResetStatement(statement, true, errCode);
178 return errCode;
179 }
180
181 if (statement == nullptr) {
182 return -E_INVALID_DB;
183 }
184
185 return E_OK;
186 }
187
ResetStatement(sqlite3_stmt * & statement,bool isNeedFinalize,int & errCode)188 void SQLiteUtils::ResetStatement(sqlite3_stmt *&statement, bool isNeedFinalize, int &errCode)
189 {
190 ResetStatement(statement, isNeedFinalize, false, errCode);
191 }
192
ResetStatement(sqlite3_stmt * & statement,bool isNeedFinalize,bool isIgnoreResetRet,int & errCode)193 void SQLiteUtils::ResetStatement(sqlite3_stmt *&statement, bool isNeedFinalize, bool isIgnoreResetRet, int &errCode)
194 {
195 if (statement == nullptr) {
196 return;
197 }
198
199 int innerCode = SQLITE_OK;
200 // if need finalize the statement, just goto finalize.
201 if (!isNeedFinalize) {
202 // reset the statement firstly.
203 innerCode = sqlite3_reset(statement);
204 if (innerCode != SQLITE_OK && !isIgnoreResetRet) {
205 LOGE("[SQLiteUtils] reset statement error:%d, sys:%d", innerCode, errno);
206 isNeedFinalize = true;
207 } else {
208 sqlite3_clear_bindings(statement);
209 }
210 }
211
212 if (isNeedFinalize) {
213 int finalizeResult = sqlite3_finalize(statement);
214 if (finalizeResult != SQLITE_OK) {
215 LOGE("[SQLiteUtils] finalize statement error:%d, sys:%d", finalizeResult, errno);
216 innerCode = finalizeResult;
217 }
218 statement = nullptr;
219 }
220
221 if (innerCode != SQLITE_OK) { // the sqlite error code has higher priority.
222 errCode = SQLiteUtils::MapSQLiteErrno(innerCode);
223 }
224 }
225
226 #ifdef RELATIONAL_STORE
227 namespace { // anonymous namespace for schema analysis
AnalysisSchemaSqlAndTrigger(sqlite3 * db,const std::string & tableName,TableInfo & table,bool caseSensitive)228 int AnalysisSchemaSqlAndTrigger(sqlite3 *db, const std::string &tableName, TableInfo &table, bool caseSensitive)
229 {
230 std::string sql = "SELECT type, sql FROM sqlite_master WHERE tbl_name = ? ";
231 if (!caseSensitive) {
232 sql += "COLLATE NOCASE";
233 }
234 sqlite3_stmt *statement = nullptr;
235 int errCode = SQLiteUtils::GetStatement(db, sql, statement);
236 if (errCode != E_OK) {
237 LOGE("[AnalysisSchema] Prepare the analysis schema sql and trigger statement error:%d", errCode);
238 return errCode;
239 }
240 errCode = SQLiteUtils::BindTextToStatement(statement, 1, tableName);
241 int ret = E_OK;
242 if (errCode != E_OK) {
243 LOGE("[AnalysisSchema] Bind table name failed:%d", errCode);
244 SQLiteUtils::ResetStatement(statement, true, ret);
245 return errCode;
246 }
247
248 errCode = -E_NOT_FOUND;
249 int err = SQLiteUtils::MapSQLiteErrno(SQLITE_ROW);
250 do {
251 err = SQLiteUtils::StepWithRetry(statement);
252 if (err == SQLiteUtils::MapSQLiteErrno(SQLITE_DONE)) {
253 break;
254 } else if (err == SQLiteUtils::MapSQLiteErrno(SQLITE_ROW)) {
255 errCode = E_OK;
256 std::string type;
257 (void) SQLiteUtils::GetColumnTextValue(statement, 0, type);
258 if (type == "table") {
259 std::string createTableSql;
260 (void) SQLiteUtils::GetColumnTextValue(statement, 1, createTableSql); // 1 means create table sql
261 table.SetCreateTableSql(createTableSql);
262 }
263 } else {
264 LOGE("[AnalysisSchema] Step for the analysis create table sql and trigger failed:%d", err);
265 errCode = err;
266 break;
267 }
268 } while (err == SQLiteUtils::MapSQLiteErrno(SQLITE_ROW));
269 SQLiteUtils::ResetStatement(statement, true, ret);
270 return errCode != E_OK ? errCode : ret;
271 }
272
AnalysisSchemaIndexDefine(sqlite3 * db,const std::string & indexName,CompositeFields & indexDefine)273 int AnalysisSchemaIndexDefine(sqlite3 *db, const std::string &indexName, CompositeFields &indexDefine)
274 {
275 auto sql = "pragma index_info('" + indexName + "')";
276 sqlite3_stmt *statement = nullptr;
277 int errCode = SQLiteUtils::GetStatement(db, sql, statement);
278 if (errCode != E_OK) {
279 LOGE("[AnalysisSchema] Prepare the analysis schema index statement error:%d", errCode);
280 return errCode;
281 }
282
283 do {
284 errCode = SQLiteUtils::StepWithRetry(statement);
285 if (errCode == SQLiteUtils::MapSQLiteErrno(SQLITE_DONE)) {
286 errCode = E_OK;
287 break;
288 } else if (errCode == SQLiteUtils::MapSQLiteErrno(SQLITE_ROW)) {
289 std::string indexField;
290 (void) SQLiteUtils::GetColumnTextValue(statement, 2, indexField); // 2 means index's column name.
291 indexDefine.push_back(indexField);
292 } else {
293 LOGW("[AnalysisSchema] Step for the analysis schema index failed:%d", errCode);
294 break;
295 }
296 } while (errCode == SQLiteUtils::MapSQLiteErrno(SQLITE_ROW));
297
298 int ret = E_OK;
299 SQLiteUtils::ResetStatement(statement, true, ret);
300 return errCode != E_OK ? errCode : ret;
301 }
302
GetSchemaIndexList(sqlite3 * db,const std::string & tableName,std::vector<std::string> & indexList,std::vector<std::string> & uniqueList)303 int GetSchemaIndexList(sqlite3 *db, const std::string &tableName, std::vector<std::string> &indexList,
304 std::vector<std::string> &uniqueList)
305 {
306 std::string sql = "pragma index_list('" + tableName + "')";
307 sqlite3_stmt *statement = nullptr;
308 int errCode = SQLiteUtils::GetStatement(db, sql, statement);
309 if (errCode != E_OK) {
310 LOGE("[AnalysisSchema] Prepare the get schema index list statement error:%d", errCode);
311 return errCode;
312 }
313
314 do {
315 errCode = SQLiteUtils::StepWithRetry(statement);
316 if (errCode == SQLiteUtils::MapSQLiteErrno(SQLITE_DONE)) {
317 errCode = E_OK;
318 break;
319 } else if (errCode == SQLiteUtils::MapSQLiteErrno(SQLITE_ROW)) {
320 std::string indexName;
321 (void) SQLiteUtils::GetColumnTextValue(statement, 1, indexName); // 1 means index name
322 int unique = sqlite3_column_int64(statement, 2); // 2 means index type, whether unique
323 if (unique == 0) { // 0 means index created by user declare
324 indexList.push_back(indexName);
325 } else if (unique == 1) { // 1 means an unique define
326 uniqueList.push_back(indexName);
327 }
328 } else {
329 LOGW("[AnalysisSchema] Step for the get schema index list failed:%d", errCode);
330 break;
331 }
332 } while (errCode == SQLiteUtils::MapSQLiteErrno(SQLITE_ROW));
333 int ret = E_OK;
334 SQLiteUtils::ResetStatement(statement, true, ret);
335 return errCode != E_OK ? errCode : ret;
336 }
337
AnalysisSchemaIndex(sqlite3 * db,const std::string & tableName,TableInfo & table)338 int AnalysisSchemaIndex(sqlite3 *db, const std::string &tableName, TableInfo &table)
339 {
340 std::vector<std::string> indexList;
341 std::vector<std::string> uniqueList;
342 int errCode = GetSchemaIndexList(db, tableName, indexList, uniqueList);
343 if (errCode != E_OK) {
344 LOGE("[AnalysisSchema] get schema index list failed.");
345 return errCode;
346 }
347
348 for (const auto &indexName : indexList) {
349 CompositeFields indexDefine;
350 errCode = AnalysisSchemaIndexDefine(db, indexName, indexDefine);
351 if (errCode != E_OK) {
352 LOGE("[AnalysisSchema] analysis schema index columns failed.");
353 return errCode;
354 }
355 table.AddIndexDefine(indexName, indexDefine);
356 }
357
358 std::vector<CompositeFields> uniques;
359 for (const auto &uniqueName : uniqueList) {
360 CompositeFields uniqueDefine;
361 errCode = AnalysisSchemaIndexDefine(db, uniqueName, uniqueDefine);
362 if (errCode != E_OK) {
363 LOGE("[AnalysisSchema] analysis schema unique columns failed.");
364 return errCode;
365 }
366 uniques.push_back(uniqueDefine);
367 }
368 table.SetUniqueDefine(uniques);
369 return E_OK;
370 }
371
SetPrimaryKeyCollateType(const std::string & sql,FieldInfo & field)372 void SetPrimaryKeyCollateType(const std::string &sql, FieldInfo &field)
373 {
374 std::string upperFieldName = DBCommon::ToUpperCase(field.GetFieldName());
375 if (DBCommon::HasConstraint(sql, "PRIMARY KEY COLLATE NOCASE", " ", " ,)") ||
376 DBCommon::HasConstraint(sql, upperFieldName + " TEXT COLLATE NOCASE", " (,", " ,")) {
377 field.SetCollateType(CollateType::COLLATE_NOCASE);
378 } else if (DBCommon::HasConstraint(sql, "PRIMARY KEY COLLATE RTRIM", " ", " ,)") ||
379 DBCommon::HasConstraint(sql, upperFieldName + " TEXT COLLATE RTRIM", " (,", " ,")) {
380 field.SetCollateType(CollateType::COLLATE_RTRIM);
381 }
382 }
383
SetFieldInfo(sqlite3_stmt * statement,TableInfo & table)384 int SetFieldInfo(sqlite3_stmt *statement, TableInfo &table)
385 {
386 FieldInfo field;
387 field.SetColumnId(sqlite3_column_int(statement, 0)); // 0 means column id index
388
389 std::string tmpString;
390 (void) SQLiteUtils::GetColumnTextValue(statement, 1, tmpString); // 1 means column name index
391 if (!DBCommon::CheckIsAlnumOrUnderscore(tmpString)) {
392 LOGE("[AnalysisSchema] unsupported field name.");
393 return -E_NOT_SUPPORT;
394 }
395 field.SetFieldName(tmpString);
396
397 (void) SQLiteUtils::GetColumnTextValue(statement, 2, tmpString); // 2 means datatype index
398 field.SetDataType(tmpString);
399
400 field.SetNotNull(static_cast<bool>(sqlite3_column_int64(statement, 3))); // 3 means whether null index
401
402 (void) SQLiteUtils::GetColumnTextValue(statement, 4, tmpString); // 4 means default value index
403 if (!tmpString.empty()) {
404 field.SetDefaultValue(tmpString);
405 }
406
407 int keyIndex = sqlite3_column_int(statement, 5); // 5 means primary key index
408 if (keyIndex != 0) { // not 0 means is a primary key
409 table.SetPrimaryKey(field.GetFieldName(), keyIndex);
410 SetPrimaryKeyCollateType(table.GetCreateTableSql(), field);
411 }
412 table.AddField(field);
413 return E_OK;
414 }
415 } // end of anonymous namespace for schema analysis
416
AnalysisSchemaFieldDefine(sqlite3 * db,const std::string & tableName,TableInfo & table)417 int SQLiteUtils::AnalysisSchemaFieldDefine(sqlite3 *db, const std::string &tableName, TableInfo &table)
418 {
419 std::string sql = "pragma table_info('" + tableName + "')";
420 sqlite3_stmt *statement = nullptr;
421 int errCode = SQLiteUtils::GetStatement(db, sql, statement);
422 if (errCode != E_OK) {
423 LOGE("[AnalysisSchema] Prepare the analysis schema field statement error:%d", errCode);
424 return errCode;
425 }
426
427 do {
428 errCode = SQLiteUtils::StepWithRetry(statement);
429 if (errCode == SQLiteUtils::MapSQLiteErrno(SQLITE_DONE)) {
430 errCode = E_OK;
431 break;
432 } else if (errCode == SQLiteUtils::MapSQLiteErrno(SQLITE_ROW)) {
433 errCode = SetFieldInfo(statement, table);
434 if (errCode != E_OK) {
435 break;
436 }
437 } else {
438 LOGW("[AnalysisSchema] Step for the analysis schema field failed:%d", errCode);
439 break;
440 }
441 } while (errCode == E_OK);
442
443 if (table.GetPrimaryKey().empty()) {
444 table.SetPrimaryKey("rowid", 1);
445 }
446
447 int ret = E_OK;
448 SQLiteUtils::ResetStatement(statement, true, ret);
449 return errCode != E_OK ? errCode : ret;
450 }
451
AnalysisSchema(sqlite3 * db,const std::string & tableName,TableInfo & table,bool caseSensitive)452 int SQLiteUtils::AnalysisSchema(sqlite3 *db, const std::string &tableName, TableInfo &table, bool caseSensitive)
453 {
454 if (db == nullptr) {
455 return -E_INVALID_DB;
456 }
457
458 if (!DBCommon::CheckIsAlnumOrUnderscore(tableName)) {
459 LOGE("[AnalysisSchema] unsupported table name.");
460 return -E_NOT_SUPPORT;
461 }
462
463 int errCode = AnalysisSchemaSqlAndTrigger(db, tableName, table, caseSensitive);
464 if (errCode != E_OK) {
465 LOGE("[AnalysisSchema] Analysis sql and trigger failed. errCode = [%d]", errCode);
466 return errCode;
467 }
468
469 errCode = AnalysisSchemaIndex(db, tableName, table);
470 if (errCode != E_OK) {
471 LOGE("[AnalysisSchema] Analysis index failed.");
472 return errCode;
473 }
474
475 errCode = AnalysisSchemaFieldDefine(db, tableName, table);
476 if (errCode != E_OK) {
477 LOGE("[AnalysisSchema] Analysis field failed.");
478 return errCode;
479 }
480
481 table.SetTableName(tableName);
482 return E_OK;
483 }
484 #endif
485
BindTextToStatement(sqlite3_stmt * statement,int index,const std::string & str)486 int SQLiteUtils::BindTextToStatement(sqlite3_stmt *statement, int index, const std::string &str)
487 {
488 if (statement == nullptr) {
489 return -E_INVALID_ARGS;
490 }
491
492 int errCode = sqlite3_bind_text(statement, index, str.c_str(), str.length(), SQLITE_TRANSIENT);
493 if (errCode != SQLITE_OK) {
494 LOGE("[SQLiteUtil][Bind text]Failed to bind the value:%d", errCode);
495 return SQLiteUtils::MapSQLiteErrno(errCode);
496 }
497
498 return E_OK;
499 }
500
ProcessStatementErrCode(sqlite3_stmt * & statement,bool isNeedFinalize,int errCode)501 int SQLiteUtils::ProcessStatementErrCode(sqlite3_stmt *&statement, bool isNeedFinalize, int errCode)
502 {
503 int ret = E_OK;
504 SQLiteUtils::ResetStatement(statement, isNeedFinalize, ret);
505 return errCode != E_OK ? errCode : ret;
506 }
507
CheckTableExists(sqlite3 * db,const std::string & tableName,bool & isCreated,bool isCheckMeta)508 int SQLiteUtils::CheckTableExists(sqlite3 *db, const std::string &tableName, bool &isCreated, bool isCheckMeta)
509 {
510 if (db == nullptr) {
511 return -1;
512 }
513
514 sqlite3_stmt *stmt = nullptr;
515 int errCode = SQLiteUtils::GetStatement(db, isCheckMeta ? CHECK_META_DB_TABLE_CREATED : CHECK_TABLE_CREATED, stmt);
516 if (errCode != SQLiteUtils::MapSQLiteErrno(SQLITE_OK)) {
517 LOGE("Get check table statement failed. err=%d", errCode);
518 return errCode;
519 }
520
521 errCode = SQLiteUtils::BindTextToStatement(stmt, 1, tableName);
522 if (errCode != SQLiteUtils::MapSQLiteErrno(SQLITE_OK)) {
523 LOGE("Bind table name to statement failed. err=%d", errCode);
524 return ProcessStatementErrCode(stmt, true, errCode);
525 }
526
527 errCode = SQLiteUtils::StepWithRetry(stmt);
528 if (errCode != SQLiteUtils::MapSQLiteErrno(SQLITE_ROW)) {
529 LOGE("Check table exists failed. err=%d", errCode); // should always return a row data
530 return ProcessStatementErrCode(stmt, true, errCode);
531 }
532 errCode = E_OK;
533 isCreated = (sqlite3_column_int(stmt, 0) == 1);
534 return ProcessStatementErrCode(stmt, true, errCode);
535 }
536
BindBlobToStatement(sqlite3_stmt * statement,int index,const std::vector<uint8_t> & value,bool permEmpty)537 int SQLiteUtils::BindBlobToStatement(sqlite3_stmt *statement, int index, const std::vector<uint8_t> &value,
538 bool permEmpty)
539 {
540 if (statement == nullptr) {
541 return -E_INVALID_ARGS;
542 }
543
544 // Check empty value.
545 if (value.empty() && !permEmpty) {
546 LOGI("[SQLiteUtil][Bind blob]Invalid value");
547 return -E_INVALID_ARGS;
548 }
549
550 int errCode;
551 if (value.empty()) {
552 errCode = sqlite3_bind_zeroblob(statement, index, -1); // -1 for zero-length blob.
553 } else {
554 errCode = sqlite3_bind_blob(statement, index, static_cast<const void *>(value.data()),
555 value.size(), SQLITE_TRANSIENT);
556 }
557
558 if (errCode != SQLITE_OK) {
559 LOGE("[SQLiteUtil][Bind blob]Failed to bind the value:%d", errCode);
560 return SQLiteUtils::MapSQLiteErrno(errCode);
561 }
562
563 return E_OK;
564 }
565
GetColumnTextValue(sqlite3_stmt * statement,int index,std::string & value)566 int SQLiteUtils::GetColumnTextValue(sqlite3_stmt *statement, int index, std::string &value)
567 {
568 if (statement == nullptr) {
569 return -E_INVALID_ARGS;
570 }
571
572 int valSize = sqlite3_column_bytes(statement, index);
573 if (valSize < 0) {
574 LOGW("[SQLiteUtils][Column Text] size less than zero:%d", valSize);
575 value = {};
576 return E_OK;
577 }
578 const unsigned char *val = sqlite3_column_text(statement, index);
579 if (valSize == 0 || val == nullptr) {
580 value = {};
581 return E_OK;
582 }
583 value = std::string(reinterpret_cast<const char *>(val));
584 if (valSize > MAX_TEXT_READ_SIZE) {
585 LOGW("[SQLiteUtils][Column text] size over limit:%d", valSize);
586 value.resize(MAX_TEXT_READ_SIZE + 1); // Reset value size to invalid
587 }
588 return E_OK;
589 }
590
GetColumnBlobValue(sqlite3_stmt * statement,int index,std::vector<uint8_t> & value)591 int SQLiteUtils::GetColumnBlobValue(sqlite3_stmt *statement, int index, std::vector<uint8_t> &value)
592 {
593 if (statement == nullptr) {
594 return -E_INVALID_ARGS;
595 }
596
597 int keySize = sqlite3_column_bytes(statement, index);
598 if (keySize < 0) {
599 LOGW("[SQLiteUtils][Column blob] size less than zero:%d", keySize);
600 value.resize(0);
601 return E_OK;
602 }
603 auto keyRead = static_cast<const uint8_t *>(sqlite3_column_blob(statement, index));
604 if (keySize == 0 || keyRead == nullptr) {
605 value.resize(0);
606 } else {
607 if (keySize > MAX_BLOB_READ_SIZE) {
608 LOGW("[SQLiteUtils][Column blob] size over limit:%d", keySize);
609 keySize = MAX_BLOB_READ_SIZE + 1;
610 }
611 value.resize(keySize);
612 value.assign(keyRead, keyRead + keySize);
613 }
614 return E_OK;
615 }
616
GetCountBySql(sqlite3 * db,const std::string & sql,int & count)617 int SQLiteUtils::GetCountBySql(sqlite3 *db, const std::string &sql, int &count)
618 {
619 sqlite3_stmt *stmt = nullptr;
620 int errCode = SQLiteUtils::GetStatement(db, sql, stmt);
621 if (errCode != E_OK) {
622 LOGE("[SQLiteUtils][GetCountBySql] Get stmt failed when get local data count: %d", errCode);
623 return errCode;
624 }
625 errCode = SQLiteUtils::StepWithRetry(stmt, false);
626 if (errCode == SQLiteUtils::MapSQLiteErrno(SQLITE_ROW)) {
627 count = static_cast<int>(sqlite3_column_int(stmt, 0));
628 errCode = E_OK;
629 } else {
630 LOGE("[SQLiteUtils][GetCountBySql] Query local data count failed: %d", errCode);
631 }
632 int ret = E_OK;
633 SQLiteUtils::ResetStatement(stmt, true, ret);
634 if (ret != E_OK) {
635 LOGE("[SQLiteUtils][GetCountBySql] Reset stmt failed when get local data count: %d", ret);
636 }
637 return errCode != E_OK ? errCode : ret;
638 }
639
BindInt64ToStatement(sqlite3_stmt * statement,int index,int64_t value)640 int SQLiteUtils::BindInt64ToStatement(sqlite3_stmt *statement, int index, int64_t value)
641 {
642 // statement check outSide
643 int errCode = sqlite3_bind_int64(statement, index, value);
644 if (errCode != SQLITE_OK) {
645 LOGE("[SQLiteUtil][Bind int64]Failed to bind the value:%d", errCode);
646 return SQLiteUtils::MapSQLiteErrno(errCode);
647 }
648
649 return E_OK;
650 }
651 } // namespace DistributedDB
652