1 /*
2 * Copyright (c) 2022 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include "sqlite_connection.h"
17
18 #include <cerrno>
19 #include <memory>
20 #include <sqlite3sym.h>
21 #include <sys/stat.h>
22 #ifdef RDB_SUPPORT_ICU
23 #include <unicode/ucol.h>
24 #endif
25
26 #include <unistd.h>
27
28 #include "file_ex.h"
29 #include "logger.h"
30 #include "rdb_errno.h"
31 #include "sqlite_errno.h"
32 #include "sqlite_global_config.h"
33 #include "sqlite_utils.h"
34 #include "raw_data_parser.h"
35
36 #if !defined(WINDOWS_PLATFORM) && !defined(MAC_PLATFORM) && !defined(ANDROID_PLATFORM) && !defined(IOS_PLATFORM)
37 #include "directory_ex.h"
38 #include "rdb_security_manager.h"
39 #include "relational/relational_store_sqlite_ext.h"
40 #include "share_block.h"
41 #include "shared_block_serializer_info.h"
42 #endif
43
44 namespace OHOS {
45 namespace NativeRdb {
46 using namespace OHOS::Rdb;
47
48 #if !defined(WINDOWS_PLATFORM) && !defined(MAC_PLATFORM)
49 // error status
50 const int ERROR_STATUS = -1;
51 #if !defined(ANDROID_PLATFORM) && !defined(IOS_PLATFORM)
52 using RdbKeyFile = RdbSecurityManager::KeyFileType;
53 #endif
54 #endif
55
Open(const RdbStoreConfig & config,bool isWriteConnection,int & errCode)56 SqliteConnection *SqliteConnection::Open(const RdbStoreConfig &config, bool isWriteConnection, int &errCode)
57 {
58 auto connection = new (std::nothrow) SqliteConnection(isWriteConnection);
59 if (connection == nullptr) {
60 LOG_ERROR("SqliteConnection::Open new failed, connection is nullptr");
61 return nullptr;
62 }
63 errCode = connection->InnerOpen(config);
64 if (errCode != E_OK) {
65 delete connection;
66 return nullptr;
67 }
68 return connection;
69 }
70
SqliteConnection(bool isWriteConnection)71 SqliteConnection::SqliteConnection(bool isWriteConnection)
72 : dbHandle(nullptr),
73 isWriteConnection(isWriteConnection),
74 isReadOnly(false),
75 statement(),
76 stepStatement(nullptr),
77 filePath(""),
78 openFlags(0),
79 inTransaction_(false)
80 {
81 }
82
GetDbPath(const RdbStoreConfig & config,std::string & dbPath)83 int SqliteConnection::GetDbPath(const RdbStoreConfig &config, std::string &dbPath)
84 {
85 if (config.GetStorageMode() == StorageMode::MODE_MEMORY) {
86 dbPath = SqliteGlobalConfig::GetMemoryDbPath();
87 } else if (config.GetPath().empty()) {
88 LOG_ERROR("SqliteConnection GetDbPath input empty database path");
89 return E_EMPTY_FILE_NAME;
90 } else if (config.GetPath().front() != '/' && config.GetPath().at(1) != ':') {
91 LOG_ERROR("SqliteConnection GetDbPath input relative path");
92 return E_RELATIVE_PATH;
93 } else {
94 dbPath = config.GetPath();
95 }
96 return E_OK;
97 }
98
InnerOpen(const RdbStoreConfig & config)99 int SqliteConnection::InnerOpen(const RdbStoreConfig &config)
100 {
101 std::string dbPath;
102 auto ret = GetDbPath(config, dbPath);
103 if (ret != E_OK) {
104 return ret;
105 }
106
107 stepStatement = std::make_shared<SqliteStatement>();
108 if (stepStatement == nullptr) {
109 return E_STEP_STATEMENT_NOT_INIT;
110 }
111 #if !defined(WINDOWS_PLATFORM) && !defined(MAC_PLATFORM)
112 bool isDbFileExist = access(dbPath.c_str(), F_OK) == 0;
113 if (!isDbFileExist && (!config.IsCreateNecessary())) {
114 LOG_ERROR("SqliteConnection InnerOpen db not exist");
115 return E_DB_NOT_EXIST;
116 }
117 #endif
118 isReadOnly = !isWriteConnection || config.IsReadOnly();
119 int openFileFlags = config.IsReadOnly() ? SQLITE_OPEN_READONLY : (SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE);
120 int errCode = sqlite3_open_v2(dbPath.c_str(), &dbHandle, openFileFlags, nullptr);
121 if (errCode != SQLITE_OK) {
122 LOG_ERROR("SqliteConnection InnerOpen fail to open database err = %{public}d", errCode);
123 #if !defined(WINDOWS_PLATFORM) && !defined(MAC_PLATFORM)
124 auto const pos = dbPath.find_last_of("\\/");
125 if (pos != std::string::npos) {
126 std::string filepath = dbPath.substr(0, pos);
127 if (access(filepath.c_str(), F_OK | W_OK) != 0) {
128 LOG_ERROR("The path to the database file to be created is not valid, err = %{public}d", errno);
129 return E_INVALID_FILE_PATH;
130 }
131 }
132 #endif
133 return SQLiteError::ErrNo(errCode);
134 }
135
136 RegDefaultFunctions(dbHandle);
137 SetPersistWal();
138 SetBusyTimeout(DEFAULT_BUSY_TIMEOUT_MS);
139 LimitPermission(dbPath);
140
141 errCode = Config(config);
142 if (errCode != E_OK) {
143 return errCode;
144 }
145
146 if (isWriteConnection) {
147 errCode = sqlite3_wal_checkpoint_v2(dbHandle, nullptr, SQLITE_CHECKPOINT_TRUNCATE, nullptr, nullptr);
148 if (errCode != SQLITE_OK) {
149 LOG_WARN("sqlite checkpoint errCode is %{public}d", errCode);
150 }
151 }
152
153 filePath = dbPath;
154 openFlags = openFileFlags;
155
156 return E_OK;
157 }
158
SetCustomFunctions(const RdbStoreConfig & config)159 int SqliteConnection::SetCustomFunctions(const RdbStoreConfig &config)
160 {
161 customScalarFunctions_ = config.GetScalarFunctions();
162 for (auto &it : customScalarFunctions_) {
163 int errCode = SetCustomScalarFunction(it.first, it.second.argc_, &it.second.function_);
164 if (errCode != E_OK) {
165 return errCode;
166 }
167 }
168 return E_OK;
169 }
170
CustomScalarFunctionCallback(sqlite3_context * ctx,int argc,sqlite3_value ** argv)171 static void CustomScalarFunctionCallback(sqlite3_context *ctx, int argc, sqlite3_value **argv)
172 {
173 if (ctx == nullptr || argv == nullptr) {
174 LOG_ERROR("ctx or argv is nullptr");
175 return;
176 }
177 auto function = static_cast<ScalarFunction *>(sqlite3_user_data(ctx));
178 if (function == nullptr) {
179 LOG_ERROR("function is nullptr");
180 return;
181 }
182
183 std::vector<std::string> argsVector;
184 for (int i = 0; i < argc; ++i) {
185 auto arg = reinterpret_cast<const char*>(sqlite3_value_text(argv[i]));
186 if (arg == nullptr) {
187 LOG_ERROR("arg is nullptr, index is %{public}d", i);
188 sqlite3_result_null(ctx);
189 return;
190 }
191 argsVector.emplace_back(std::string(arg));
192 }
193
194 std::string result = (*function)(argsVector);
195 if (result.empty()) {
196 sqlite3_result_null(ctx);
197 return;
198 }
199 sqlite3_result_text(ctx, result.c_str(), -1, SQLITE_TRANSIENT);
200 }
201
SetCustomScalarFunction(const std::string & functionName,int argc,ScalarFunction * function)202 int SqliteConnection::SetCustomScalarFunction(const std::string &functionName, int argc, ScalarFunction *function)
203 {
204 int err = sqlite3_create_function_v2(dbHandle,
205 functionName.c_str(),
206 argc,
207 SQLITE_UTF8,
208 function,
209 &CustomScalarFunctionCallback,
210 nullptr,
211 nullptr,
212 nullptr);
213 if (err != SQLITE_OK) {
214 LOG_ERROR("SetCustomScalarFunction errCode is %{public}d", err);
215 }
216 return err;
217 }
218
Config(const RdbStoreConfig & config)219 int SqliteConnection::Config(const RdbStoreConfig &config)
220 {
221 if (config.GetStorageMode() == StorageMode::MODE_MEMORY) {
222 return E_OK;
223 }
224
225 int errCode = SetPageSize(config);
226 if (errCode != E_OK) {
227 return errCode;
228 }
229
230 errCode = SetEncryptKey(config);
231 if (errCode != E_OK) {
232 return errCode;
233 }
234
235 errCode = SetJournalMode(config);
236 if (errCode != E_OK) {
237 return errCode;
238 }
239
240 errCode = SetJournalSizeLimit(config);
241 if (errCode != E_OK) {
242 return errCode;
243 }
244
245 errCode = SetAutoCheckpoint(config);
246 if (errCode != E_OK) {
247 return errCode;
248 }
249
250 errCode = SetCustomFunctions(config);
251 if (errCode != E_OK) {
252 return errCode;
253 }
254
255 return E_OK;
256 }
257
~SqliteConnection()258 SqliteConnection::~SqliteConnection()
259 {
260 if (dbHandle != nullptr) {
261 statement.Finalize();
262 if (stepStatement != nullptr) {
263 stepStatement->Finalize();
264 }
265 int errCode = sqlite3_close_v2(dbHandle);
266 if (errCode != SQLITE_OK) {
267 LOG_ERROR("SqliteConnection ~SqliteConnection: could not close database err = %{public}d", errCode);
268 }
269 }
270 }
271
SetPageSize(const RdbStoreConfig & config)272 int SqliteConnection::SetPageSize(const RdbStoreConfig &config)
273 {
274 if (isReadOnly || config.GetPageSize() == GlobalExpr::DB_PAGE_SIZE) {
275 return E_OK;
276 }
277
278 int targetValue = config.GetPageSize();
279 int64_t value = 0;
280 int errCode = ExecuteGetLong(value, "PRAGMA page_size");
281 if (errCode != E_OK) {
282 LOG_ERROR("SqliteConnection SetPageSize fail to get page size : %{public}d", errCode);
283 return errCode;
284 }
285
286 if (value == targetValue) {
287 return E_OK;
288 }
289
290 errCode = ExecuteSql("PRAGMA page_size=" + std::to_string(targetValue));
291 if (errCode != E_OK) {
292 LOG_ERROR("SqliteConnection SetPageSize fail to set page size : %{public}d", errCode);
293 }
294 return errCode;
295 }
296
SetEncryptKey(const RdbStoreConfig & config)297 int SqliteConnection::SetEncryptKey(const RdbStoreConfig &config)
298 {
299 #if !defined(WINDOWS_PLATFORM) && !defined(MAC_PLATFORM) && !defined(ANDROID_PLATFORM) && !defined(IOS_PLATFORM)
300 std::vector<uint8_t> key = config.GetEncryptKey();
301 RdbPassword rdbPwd;
302 if (config.IsEncrypt()) {
303 RdbSecurityManager::GetInstance().Init(config.GetBundleName(), config.GetPath());
304 rdbPwd = RdbSecurityManager::GetInstance().GetRdbPassword(RdbKeyFile::PUB_KEY_FILE);
305 key.assign(key.size(), 0);
306 key = std::vector<uint8_t>(rdbPwd.GetData(), rdbPwd.GetData() + rdbPwd.GetSize());
307 } else if (key.empty()) {
308 return E_OK;
309 }
310
311 int errCode = sqlite3_key(dbHandle, static_cast<const void *>(key.data()), static_cast<int>(key.size()));
312 key.assign(key.size(), 0);
313 if (errCode != SQLITE_OK) {
314 LOG_ERROR("SqliteConnection SetEncryptKey fail, err = %{public}d", errCode);
315 return SQLiteError::ErrNo(errCode);
316 }
317
318 errCode = ExecuteSql(GlobalExpr::CODEC_HMAC_ALGO);
319 if (errCode != E_OK) {
320 LOG_ERROR("SqliteConnection set sha algo failed, err = %{public}d", errCode);
321 return errCode;
322 }
323 errCode = ExecuteSql(GlobalExpr::CODEC_REKEY_HMAC_ALGO);
324 if (errCode != E_OK) {
325 LOG_ERROR("SqliteConnection set rekey sha algo failed, err = %{public}d", errCode);
326 return errCode;
327 }
328
329 if (rdbPwd.isKeyExpired) {
330 rdbPwd = RdbSecurityManager::GetInstance().GetRdbPassword(RdbKeyFile::PUB_KEY_FILE_NEW_KEY);
331 if (!rdbPwd.IsValid()) {
332 RdbSecurityManager::GetInstance().DelRdbSecretDataFile(RdbKeyFile::PUB_KEY_FILE_NEW_KEY);
333 LOG_ERROR("new key is not valid.");
334 return E_OK;
335 }
336 key = std::vector<uint8_t>(rdbPwd.GetData(), rdbPwd.GetData() + rdbPwd.GetSize());
337 errCode = sqlite3_rekey(dbHandle, static_cast<const void *>(key.data()), static_cast<int>(key.size()));
338 key.assign(key.size(), 0);
339 if (errCode != SQLITE_OK) {
340 LOG_ERROR("ReKey failed, err = %{public}d", errCode);
341 RdbSecurityManager::GetInstance().DelRdbSecretDataFile(RdbKeyFile::PUB_KEY_FILE_NEW_KEY);
342 return E_OK;
343 }
344
345 RdbSecurityManager::GetInstance().UpdateKeyFile();
346 }
347 #endif
348 return E_OK;
349 }
350
SetPersistWal()351 int SqliteConnection::SetPersistWal()
352 {
353 int opcode = 1;
354 int errCode = sqlite3_file_control(dbHandle, "main", SQLITE_FCNTL_PERSIST_WAL, &opcode);
355 if (errCode != SQLITE_OK) {
356 LOG_ERROR("failed");
357 return E_SET_PERSIST_WAL;
358 }
359 return E_OK;
360 }
361
SetBusyTimeout(int timeout)362 int SqliteConnection::SetBusyTimeout(int timeout)
363 {
364 auto errCode = sqlite3_busy_timeout(dbHandle, timeout);
365 if (errCode != SQLITE_OK) {
366 LOG_ERROR("set buys timeout failed, errCode=%{public}d", errCode);
367 return errCode;
368 }
369 return E_OK;
370 }
371
RegDefaultFunctions(sqlite3 * dbHandle)372 int SqliteConnection::RegDefaultFunctions(sqlite3 *dbHandle)
373 {
374 if (dbHandle == nullptr) {
375 return SQLITE_OK;
376 }
377 // The number of parameters is 2
378 return sqlite3_create_function_v2(dbHandle, "merge_assets", 2, SQLITE_UTF8 | SQLITE_DETERMINISTIC, nullptr,
379 &MergeAssets, nullptr, nullptr, nullptr);
380 }
381
SetJournalMode(const RdbStoreConfig & config)382 int SqliteConnection::SetJournalMode(const RdbStoreConfig &config)
383 {
384 if (isReadOnly || config.GetJournalMode().compare(GlobalExpr::DB_DEFAULT_JOURNAL_MODE) == 0) {
385 return E_OK;
386 }
387
388 std::string currentMode;
389 int errCode = ExecuteGetString(currentMode, "PRAGMA journal_mode");
390 if (errCode != E_OK) {
391 LOG_ERROR("SqliteConnection SetJournalMode fail to get journal mode : %{public}d", errCode);
392 return errCode;
393 }
394
395 currentMode = SqliteUtils::StrToUpper(currentMode);
396 if (currentMode != config.GetJournalMode()) {
397 std::string result;
398 int errorCode = ExecuteGetString(result, "PRAGMA journal_mode=" + config.GetJournalMode());
399 if (errorCode != E_OK) {
400 LOG_ERROR("SqliteConnection SetJournalMode: fail to set journal mode err=%{public}d", errorCode);
401 return errorCode;
402 }
403
404 if (SqliteUtils::StrToUpper(result) != config.GetJournalMode()) {
405 LOG_ERROR("SqliteConnection SetJournalMode: result incorrect");
406 return E_EXECUTE_RESULT_INCORRECT;
407 }
408 }
409
410 if (config.GetJournalMode() == "WAL") {
411 errCode = SetWalSyncMode(config.GetSyncMode());
412 }
413
414 return errCode;
415 }
416
SetJournalSizeLimit(const RdbStoreConfig & config)417 int SqliteConnection::SetJournalSizeLimit(const RdbStoreConfig &config)
418 {
419 if (isReadOnly || config.GetJournalSize() == GlobalExpr::DB_JOURNAL_SIZE) {
420 return E_OK;
421 }
422
423 int targetValue = SqliteGlobalConfig::GetJournalFileSize();
424 int64_t currentValue = 0;
425 int errCode = ExecuteGetLong(currentValue, "PRAGMA journal_size_limit");
426 if (errCode != E_OK) {
427 LOG_ERROR("SqliteConnection SetJournalSizeLimit fail to get journal_size_limit : %{public}d", errCode);
428 return errCode;
429 }
430
431 if (currentValue == targetValue) {
432 return E_OK;
433 }
434
435 int64_t result;
436 errCode = ExecuteGetLong(result, "PRAGMA journal_size_limit=" + std::to_string(targetValue));
437 if (errCode != E_OK) {
438 LOG_ERROR("SqliteConnection SetJournalSizeLimit fail to set journal_size_limit : %{public}d", errCode);
439 }
440 return errCode;
441 }
442
SetAutoCheckpoint(const RdbStoreConfig & config)443 int SqliteConnection::SetAutoCheckpoint(const RdbStoreConfig &config)
444 {
445 if (isReadOnly || config.IsAutoCheck() == GlobalExpr::DB_AUTO_CHECK) {
446 return E_OK;
447 }
448
449 int targetValue = SqliteGlobalConfig::GetWalAutoCheckpoint();
450 int64_t value = 0;
451 int errCode = ExecuteGetLong(value, "PRAGMA wal_autocheckpoint");
452 if (errCode != E_OK) {
453 LOG_ERROR("SqliteConnection SetAutoCheckpoint fail to get wal_autocheckpoint : %{public}d", errCode);
454 return errCode;
455 }
456
457 if (value == targetValue) {
458 return E_OK;
459 }
460
461 int64_t result;
462 errCode = ExecuteGetLong(result, "PRAGMA wal_autocheckpoint=" + std::to_string(targetValue));
463 if (errCode != E_OK) {
464 LOG_ERROR("SqliteConnection SetAutoCheckpoint fail to set wal_autocheckpoint : %{public}d", errCode);
465 }
466 return errCode;
467 }
468
SetWalSyncMode(const std::string & syncMode)469 int SqliteConnection::SetWalSyncMode(const std::string &syncMode)
470 {
471 std::string targetValue = SqliteGlobalConfig::GetWalSyncMode();
472 if (syncMode.length() != 0) {
473 targetValue = syncMode;
474 }
475
476 std::string value;
477 int errCode = ExecuteGetString(value, "PRAGMA synchronous");
478 if (errCode != E_OK) {
479 LOG_ERROR("SqliteConnection setWalSyncMode fail to get synchronous mode : %{public}d", errCode);
480 return errCode;
481 }
482
483 value = SqliteUtils::StrToUpper(value);
484 if (value == targetValue) {
485 return E_OK;
486 }
487
488 errCode = ExecuteSql("PRAGMA synchronous=" + targetValue);
489 if (errCode != E_OK) {
490 LOG_ERROR("SqliteConnection setWalSyncMode fail to set synchronous mode : %{public}d", errCode);
491 }
492 return errCode;
493 }
494
IsWriteConnection() const495 bool SqliteConnection::IsWriteConnection() const
496 {
497 return isWriteConnection;
498 }
499
Prepare(const std::string & sql,bool & outIsReadOnly)500 int SqliteConnection::Prepare(const std::string &sql, bool &outIsReadOnly)
501 {
502 int errCode = statement.Prepare(dbHandle, sql);
503 if (errCode != E_OK) {
504 return errCode;
505 }
506 outIsReadOnly = statement.IsReadOnly();
507 return E_OK;
508 }
509
PrepareAndGetInfo(const std::string & sql,bool & outIsReadOnly,int & numParameters,std::vector<std::string> & columnNames)510 int SqliteConnection::PrepareAndGetInfo(const std::string &sql, bool &outIsReadOnly, int &numParameters,
511 std::vector<std::string> &columnNames)
512 {
513 int errCode = statement.Prepare(dbHandle, sql);
514 if (errCode != E_OK) {
515 return errCode;
516 }
517
518 errCode = statement.GetColumnCount(numParameters);
519 if (errCode != E_OK) {
520 return errCode;
521 }
522
523 int columnCount;
524 errCode = statement.GetColumnCount(columnCount);
525 if (errCode != E_OK) {
526 return errCode;
527 }
528 for (int i = 0; i < columnCount; i++) {
529 std::string name;
530 statement.GetColumnName(i, name);
531 columnNames.push_back(name);
532 }
533 outIsReadOnly = statement.IsReadOnly();
534
535 errCode = statement.GetNumParameters(numParameters);
536 if (errCode != E_OK) {
537 return errCode;
538 }
539
540 return E_OK;
541 }
542
PrepareAndBind(const std::string & sql,const std::vector<ValueObject> & bindArgs)543 int SqliteConnection::PrepareAndBind(const std::string &sql, const std::vector<ValueObject> &bindArgs)
544 {
545 if (dbHandle == nullptr) {
546 LOG_ERROR("SqliteConnection dbHandle is nullptr");
547 return E_INVALID_STATEMENT;
548 }
549
550 int errCode = LimitWalSize();
551 if (errCode != E_OK) {
552 return errCode;
553 }
554
555 errCode = statement.Prepare(dbHandle, sql);
556 if (errCode != E_OK) {
557 return errCode;
558 }
559
560 if (!isWriteConnection && !statement.IsReadOnly()) {
561 return E_EXECUTE_WRITE_IN_READ_CONNECTION;
562 }
563
564 errCode = statement.BindArguments(bindArgs);
565 return errCode;
566 }
567
ExecuteSql(const std::string & sql,const std::vector<ValueObject> & bindArgs)568 int SqliteConnection::ExecuteSql(const std::string &sql, const std::vector<ValueObject> &bindArgs)
569 {
570 int errCode = PrepareAndBind(sql, bindArgs);
571 if (errCode != E_OK) {
572 return errCode;
573 }
574
575 errCode = statement.Step();
576 if (errCode == SQLITE_ROW) {
577 LOG_ERROR("SqliteConnection Execute : Queries can be performed using query or QuerySql methods only");
578 statement.ResetStatementAndClearBindings();
579 return E_QUERY_IN_EXECUTE;
580 } else if (errCode != SQLITE_DONE) {
581 LOG_ERROR("SqliteConnection Execute : err %{public}d", errCode);
582 statement.ResetStatementAndClearBindings();
583 return SQLiteError::ErrNo(errCode);
584 }
585
586 errCode = statement.ResetStatementAndClearBindings();
587 return errCode;
588 }
589
ExecuteForChangedRowCount(int & changedRows,const std::string & sql,const std::vector<ValueObject> & bindArgs)590 int SqliteConnection::ExecuteForChangedRowCount(
591 int &changedRows, const std::string &sql, const std::vector<ValueObject> &bindArgs)
592 {
593 int errCode = PrepareAndBind(sql, bindArgs);
594 if (errCode != E_OK) {
595 return errCode;
596 }
597
598 errCode = statement.Step();
599 if (errCode == SQLITE_ROW) {
600 LOG_ERROR("SqliteConnection ExecuteForChangedRowCount : Queries can be performed using query or QuerySql "
601 "methods only");
602 statement.ResetStatementAndClearBindings();
603 return E_QUERY_IN_EXECUTE;
604 } else if (errCode != SQLITE_DONE) {
605 LOG_ERROR("SqliteConnection ExecuteForChangedRowCount : failed %{public}d", errCode);
606 statement.ResetStatementAndClearBindings();
607 return SQLiteError::ErrNo(errCode);
608 }
609
610 changedRows = sqlite3_changes(dbHandle);
611 errCode = statement.ResetStatementAndClearBindings();
612 return errCode;
613 }
614
ExecuteForLastInsertedRowId(int64_t & outRowId,const std::string & sql,const std::vector<ValueObject> & bindArgs)615 int SqliteConnection::ExecuteForLastInsertedRowId(
616 int64_t &outRowId, const std::string &sql, const std::vector<ValueObject> &bindArgs)
617 {
618 int errCode = PrepareAndBind(sql, bindArgs);
619 if (errCode != E_OK) {
620 return errCode;
621 }
622
623 errCode = statement.Step();
624 if (errCode == SQLITE_ROW) {
625 LOG_ERROR("SqliteConnection ExecuteForLastInsertedRowId : Queries can be performed using query or QuerySql "
626 "methods only");
627 statement.ResetStatementAndClearBindings();
628 return E_QUERY_IN_EXECUTE;
629 } else if (errCode != SQLITE_DONE) {
630 LOG_ERROR("SqliteConnection ExecuteForLastInsertedRowId : failed %{public}d", errCode);
631 statement.ResetStatementAndClearBindings();
632 return SQLiteError::ErrNo(errCode);
633 }
634
635 outRowId = (sqlite3_changes(dbHandle) > 0) ? sqlite3_last_insert_rowid(dbHandle) : -1;
636 errCode = statement.ResetStatementAndClearBindings();
637 return errCode;
638 }
639
ExecuteGetLong(int64_t & outValue,const std::string & sql,const std::vector<ValueObject> & bindArgs)640 int SqliteConnection::ExecuteGetLong(
641 int64_t &outValue, const std::string &sql, const std::vector<ValueObject> &bindArgs)
642 {
643 int errCode = PrepareAndBind(sql, bindArgs);
644 if (errCode != E_OK) {
645 return errCode;
646 }
647
648 errCode = statement.Step();
649 if (errCode != SQLITE_ROW) {
650 statement.ResetStatementAndClearBindings();
651 LOG_ERROR("Maybe sql is not available here ERROR is %{public}d.", errCode);
652 return errCode;
653 }
654
655 errCode = statement.GetColumnLong(0, outValue);
656 if (errCode != E_OK) {
657 statement.ResetStatementAndClearBindings();
658 return errCode;
659 }
660
661 errCode = statement.ResetStatementAndClearBindings();
662 return errCode;
663 }
664
ExecuteGetString(std::string & outValue,const std::string & sql,const std::vector<ValueObject> & bindArgs)665 int SqliteConnection::ExecuteGetString(
666 std::string &outValue, const std::string &sql, const std::vector<ValueObject> &bindArgs)
667 {
668 int errCode = PrepareAndBind(sql, bindArgs);
669 if (errCode != E_OK) {
670 return errCode;
671 }
672
673 errCode = statement.Step();
674 if (errCode != SQLITE_ROW) {
675 statement.ResetStatementAndClearBindings();
676 return E_NO_ROW_IN_QUERY;
677 }
678
679 errCode = statement.GetColumnString(0, outValue);
680 if (errCode != E_OK) {
681 statement.ResetStatementAndClearBindings();
682 return errCode;
683 }
684
685 errCode = statement.ResetStatementAndClearBindings();
686 return errCode;
687 }
688
BeginStepQuery(int & errCode,const std::string & sql,const std::vector<ValueObject> & args) const689 std::shared_ptr<SqliteStatement> SqliteConnection::BeginStepQuery(int &errCode, const std::string &sql,
690 const std::vector<ValueObject> &args) const
691 {
692 errCode = stepStatement->Prepare(dbHandle, sql);
693 if (errCode != E_OK) {
694 return nullptr;
695 }
696 errCode = stepStatement->BindArguments(args);
697 if (errCode != E_OK) {
698 return nullptr;
699 }
700 return stepStatement;
701 }
702
DesFinalize()703 int SqliteConnection::DesFinalize()
704 {
705 int errCode = 0;
706 errCode = statement.Finalize();
707 if (errCode != SQLITE_OK) {
708 return errCode;
709 }
710
711 errCode = stepStatement->Finalize();
712 if (errCode != SQLITE_OK) {
713 return errCode;
714 }
715
716 if (dbHandle != nullptr) {
717 sqlite3_db_release_memory(dbHandle);
718 }
719 return errCode;
720 }
721
EndStepQuery()722 int SqliteConnection::EndStepQuery()
723 {
724 return stepStatement->ResetStatementAndClearBindings();
725 }
726
LimitPermission(const std::string & dbPath) const727 void SqliteConnection::LimitPermission(const std::string &dbPath) const
728 {
729 struct stat st = { 0 };
730 if (stat(dbPath.c_str(), &st) == 0) {
731 if ((st.st_mode & (S_IXUSR | S_IXGRP | S_IRWXO)) != 0) {
732 int ret = chmod(dbPath.c_str(), st.st_mode & (S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP));
733 if (ret != 0) {
734 LOG_ERROR("SqliteConnection LimitPermission chmod fail, err = %{public}d", errno);
735 }
736 }
737 } else {
738 LOG_ERROR("SqliteConnection LimitPermission stat fail, err = %{public}d", errno);
739 }
740 }
741
742 #ifdef RDB_SUPPORT_ICU
Collate8Compare(void * p,int n1,const void * v1,int n2,const void * v2)743 int Collate8Compare(void *p, int n1, const void *v1, int n2, const void *v2)
744 {
745 UCollator *coll = reinterpret_cast<UCollator *>(p);
746 UCharIterator i1, i2;
747 UErrorCode status = U_ZERO_ERROR;
748
749 uiter_setUTF8(&i1, (const char *)v1, n1);
750 uiter_setUTF8(&i2, (const char *)v2, n2);
751
752 UCollationResult result = ucol_strcollIter(coll, &i1, &i2, &status);
753
754 if (U_FAILURE(status)) {
755 LOG_ERROR("Ucol strcoll error.");
756 }
757
758 if (result == UCOL_LESS) {
759 return -1;
760 } else if (result == UCOL_GREATER) {
761 return 1;
762 }
763 return 0;
764 }
765
LocalizedCollatorDestroy(UCollator * collator)766 void LocalizedCollatorDestroy(UCollator *collator)
767 {
768 ucol_close(collator);
769 }
770
771 /**
772 * The database locale.
773 */
ConfigLocale(const std::string localeStr)774 int SqliteConnection::ConfigLocale(const std::string localeStr)
775 {
776 std::unique_lock<std::mutex> lock(rdbMutex);
777 UErrorCode status = U_ZERO_ERROR;
778 UCollator *collator = ucol_open(localeStr.c_str(), &status);
779 if (U_FAILURE(status)) {
780 LOG_ERROR("Can not open collator.");
781 return E_ERROR;
782 }
783 ucol_setAttribute(collator, UCOL_STRENGTH, UCOL_PRIMARY, &status);
784 if (U_FAILURE(status)) {
785 LOG_ERROR("Set attribute of collator failed.");
786 return E_ERROR;
787 }
788
789 int err = sqlite3_create_collation_v2(dbHandle, "LOCALES", SQLITE_UTF8, collator, Collate8Compare,
790 (void (*)(void *))LocalizedCollatorDestroy);
791 if (err != SQLITE_OK) {
792 LOG_ERROR("SCreate collator in sqlite3 failed.");
793 return err;
794 }
795
796 return E_OK;
797 }
798 #endif
799
800 #if !defined(WINDOWS_PLATFORM) && !defined(MAC_PLATFORM) && !defined(ANDROID_PLATFORM) && !defined(IOS_PLATFORM)
801 /**
802 * Executes a statement and populates the specified with a range of results.
803 */
ExecuteForSharedBlock(int & rowNum,std::string sql,const std::vector<ValueObject> & bindArgs,AppDataFwk::SharedBlock * sharedBlock,int startPos,int requiredPos,bool isCountAllRows)804 int SqliteConnection::ExecuteForSharedBlock(int &rowNum, std::string sql, const std::vector<ValueObject> &bindArgs,
805 AppDataFwk::SharedBlock *sharedBlock, int startPos, int requiredPos, bool isCountAllRows)
806 {
807 if (sharedBlock == nullptr) {
808 LOG_ERROR("ExecuteForSharedBlock:sharedBlock is null.");
809 return E_ERROR;
810 }
811
812 SqliteConnectionS connection(this->dbHandle, this->openFlags, this->filePath);
813 int errCode = PrepareAndBind(sql, bindArgs);
814 if (errCode != E_OK) {
815 LOG_ERROR("PrepareAndBind sql and bindArgs error = %{public}d ", errCode);
816 return errCode;
817 }
818
819 if (ClearSharedBlock(sharedBlock) == ERROR_STATUS) {
820 LOG_ERROR("ExecuteForSharedBlock:sharedBlock is null.");
821 return E_ERROR;
822 }
823
824 sqlite3_stmt *tempSqlite3St = statement.GetSql3Stmt();
825 int columnNum = sqlite3_column_count(tempSqlite3St);
826 if (SharedBlockSetColumnNum(sharedBlock, columnNum) == ERROR_STATUS) {
827 LOG_ERROR("ExecuteForSharedBlock:sharedBlock is null.");
828 return E_ERROR;
829 }
830
831 SharedBlockInfo sharedBlockInfo(&connection, sharedBlock, tempSqlite3St);
832 sharedBlockInfo.requiredPos = requiredPos;
833 sharedBlockInfo.columnNum = columnNum;
834 sharedBlockInfo.isCountAllRows = isCountAllRows;
835 sharedBlockInfo.startPos = startPos;
836
837 int rc = sqlite3_db_config(connection.db, SQLITE_DBCONFIG_USE_SHAREDBLOCK);
838 if (rc == SQLITE_OK) {
839 FillSharedBlockOpt(&sharedBlockInfo);
840 } else {
841 FillSharedBlock(&sharedBlockInfo);
842 }
843
844 if (!ResetStatement(&sharedBlockInfo)) {
845 return E_ERROR;
846 }
847 rowNum = static_cast<int>(GetCombinedData(sharedBlockInfo.startPos, sharedBlockInfo.totalRows));
848 errCode = statement.ResetStatementAndClearBindings();
849 return errCode;
850 }
851 #endif
852
SetInTransaction(bool transaction)853 void SqliteConnection::SetInTransaction(bool transaction)
854 {
855 inTransaction_ = transaction;
856 }
857
IsInTransaction()858 bool SqliteConnection::IsInTransaction()
859 {
860 return inTransaction_;
861 }
862
LimitWalSize()863 int SqliteConnection::LimitWalSize()
864 {
865 if (!isWriteConnection) {
866 return E_OK;
867 }
868
869 std::string walName = sqlite3_filename_wal(sqlite3_db_filename(dbHandle, "main"));
870 if (SqliteUtils::GetFileSize(walName) <= GlobalExpr::DB_WAL_SIZE_LIMIT) {
871 return E_OK;
872 }
873
874 int errCode = sqlite3_wal_checkpoint_v2(dbHandle, nullptr, SQLITE_CHECKPOINT_TRUNCATE, nullptr, nullptr);
875 if (errCode != SQLITE_OK) {
876 return E_WAL_SIZE_OVER_LIMIT;
877 }
878
879 int fileSize = SqliteUtils::GetFileSize(walName);
880 if (fileSize > GlobalExpr::DB_WAL_SIZE_LIMIT) {
881 LOG_ERROR("the WAL file size over default limit, %{public}s size is %{public}d",
882 SqliteUtils::Anonymous(walName).c_str(), fileSize);
883 return E_WAL_SIZE_OVER_LIMIT;
884 }
885
886 return E_OK;
887 }
888
MergeAssets(sqlite3_context * ctx,int argc,sqlite3_value ** argv)889 void SqliteConnection::MergeAssets(sqlite3_context *ctx, int argc, sqlite3_value **argv)
890 {
891 LOG_DEBUG("merge assets begin");
892 // 2 is the number of parameters
893 if (ctx == nullptr || argc != 2 || argv == nullptr) {
894 LOG_ERROR("Parameter does not meet restrictions.");
895 return;
896 }
897 std::map<std::string, ValueObject::Asset> assets;
898 auto data = static_cast<const uint8_t *>(sqlite3_value_blob(argv[0]));
899 if (data != nullptr) {
900 int len = sqlite3_value_bytes(argv[0]);
901 RawDataParser::ParserRawData(data, len, assets);
902 }
903 LOG_DEBUG("merge assets get old assets");
904 std::map<std::string, ValueObject::Asset> newAssets;
905 data = static_cast<const uint8_t *>(sqlite3_value_blob(argv[1]));
906 if (data != nullptr) {
907 int len = sqlite3_value_bytes(argv[1]);
908 RawDataParser::ParserRawData(data, len, newAssets);
909 }
910 LOG_DEBUG("merge assets get new assets");
911 CompAssets(assets, newAssets);
912 LOG_DEBUG("merge assets comp assets");
913 auto blob = RawDataParser::PackageRawData(assets);
914 sqlite3_result_blob(ctx, blob.data(), blob.size(), SQLITE_TRANSIENT);
915 }
916
CompAssets(std::map<std::string,ValueObject::Asset> & assets,std::map<std::string,ValueObject::Asset> & newAssets)917 void SqliteConnection::CompAssets(std::map<std::string, ValueObject::Asset> &assets, std::map<std::string,
918 ValueObject::Asset> &newAssets)
919 {
920 using Status = ValueObject::Asset::Status;
921 auto oldIt = assets.begin();
922 auto newIt = newAssets.begin();
923 for (; oldIt != assets.end() && newIt != newAssets.end();) {
924 if (oldIt->first == newIt->first) {
925 if (newIt->second.status == Status::STATUS_DELETE) {
926 oldIt->second.status = Status::STATUS_DELETE;
927 oldIt->second.hash = "";
928 oldIt->second.modifyTime = "";
929 oldIt->second.size = "";
930 } else {
931 MergeAsset(oldIt->second, newIt->second);
932 }
933 oldIt++;
934 newIt = newAssets.erase(newIt);
935 continue;
936 }
937 if (oldIt->first < newIt->first) {
938 ++oldIt;
939 continue;
940 }
941 newIt++;
942 }
943 for (auto &[key, value] : newAssets) {
944 value.status = ValueObject::Asset::Status::STATUS_INSERT;
945 assets.insert(std::pair{key, std::move(value)});
946 }
947 }
948
MergeAsset(ValueObject::Asset & oldAsset,ValueObject::Asset & newAsset)949 void SqliteConnection::MergeAsset(ValueObject::Asset &oldAsset, ValueObject::Asset &newAsset)
950 {
951 using Status = ValueObject::Asset::Status;
952 auto status = static_cast<int32_t>(oldAsset.status);
953 switch (status) {
954 case Status::STATUS_UNKNOWN:
955 case Status::STATUS_NORMAL:
956 case Status::STATUS_ABNORMAL:
957 case Status::STATUS_INSERT:
958 case Status::STATUS_UPDATE:
959 if (oldAsset.modifyTime != newAsset.modifyTime || oldAsset.size != newAsset.size ||
960 oldAsset.uri != newAsset.uri || oldAsset.path != newAsset.path) {
961 oldAsset.version = newAsset.version;
962 oldAsset.expiresTime = newAsset.expiresTime;
963 oldAsset.uri = newAsset.uri;
964 oldAsset.createTime = newAsset.createTime;
965 oldAsset.modifyTime = newAsset.modifyTime;
966 oldAsset.size = newAsset.size;
967 oldAsset.hash = newAsset.hash;
968 oldAsset.path = newAsset.path;
969 oldAsset.status = Status ::STATUS_UPDATE;
970 }
971 return;
972 default:
973 return;
974 }
975 }
976 } // namespace NativeRdb
977 } // namespace OHOS
978