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