diff --git a/native/android/app/CMakeLists.txt b/native/android/app/CMakeLists.txt --- a/native/android/app/CMakeLists.txt +++ b/native/android/app/CMakeLists.txt @@ -217,6 +217,8 @@ -DSQLITE_HAS_CODEC -DSQLITE_TEMP_STORE=2 -DSQLCIPHER_CRYPTO_OPENSSL + -DSQLITE_ENABLE_SESSION + -DSQLITE_ENABLE_PREUPDATE_HOOK ) target_link_libraries( diff --git a/native/cpp/CommonCpp/DatabaseManagers/CMakeLists.txt b/native/cpp/CommonCpp/DatabaseManagers/CMakeLists.txt --- a/native/cpp/CommonCpp/DatabaseManagers/CMakeLists.txt +++ b/native/cpp/CommonCpp/DatabaseManagers/CMakeLists.txt @@ -7,6 +7,8 @@ "DatabaseManager.h" "DatabaseQueryExecutor.h" "SQLiteQueryExecutor.h" + "SQLiteConnectionManager.h" + "NativeSQLiteConnectionManager.h" "entities/SQLiteStatementWrapper.h" "entities/EntityQueryHelpers.h" "entities/SQLiteDataConverters.h" @@ -21,6 +23,8 @@ set(DBM_SRCS "SQLiteQueryExecutor.cpp" + "SQLiteConnectionManager.cpp" + "NativeSQLiteConnectionManager.cpp" "entities/SQLiteDataConverters.cpp" "entities/SQLiteStatementWrapper.cpp" ) diff --git a/native/cpp/CommonCpp/DatabaseManagers/DatabaseQueryExecutor.h b/native/cpp/CommonCpp/DatabaseManagers/DatabaseQueryExecutor.h --- a/native/cpp/CommonCpp/DatabaseManagers/DatabaseQueryExecutor.h +++ b/native/cpp/CommonCpp/DatabaseManagers/DatabaseQueryExecutor.h @@ -100,6 +100,7 @@ virtual NullableString getOlmPersistAccountDataWeb() const = 0; #else virtual void createMainCompaction(std::string backupID) const = 0; + virtual void captureBackupLogs() const = 0; #endif }; diff --git a/native/cpp/CommonCpp/DatabaseManagers/NativeSQLiteConnectionManager.h b/native/cpp/CommonCpp/DatabaseManagers/NativeSQLiteConnectionManager.h new file mode 100644 --- /dev/null +++ b/native/cpp/CommonCpp/DatabaseManagers/NativeSQLiteConnectionManager.h @@ -0,0 +1,28 @@ +#pragma once + +#include "SQLiteConnectionManager.h" + +namespace comm { +class NativeSQLiteConnectionManager : public SQLiteConnectionManager { +private: + sqlite3_session *backupLogsSession; + + void attachSession(); + void detachSession(); + void persistLog( + std::string backupID, + std::string logID, + std::uint8_t *patchsetPtr, + int patchsetSize); + +public: + NativeSQLiteConnectionManager(); + void setLogsMonitoring(bool enabled); + void initializeConnection( + std::string sqliteFilePath, + std::function on_db_open_callback) override; + void closeConnection() override; + ~NativeSQLiteConnectionManager(); + bool captureLogs(std::string backupID, std::string logID); +}; +} // namespace comm diff --git a/native/cpp/CommonCpp/DatabaseManagers/NativeSQLiteConnectionManager.cpp b/native/cpp/CommonCpp/DatabaseManagers/NativeSQLiteConnectionManager.cpp new file mode 100644 --- /dev/null +++ b/native/cpp/CommonCpp/DatabaseManagers/NativeSQLiteConnectionManager.cpp @@ -0,0 +1,126 @@ +#include "NativeSQLiteConnectionManager.h" +#include "PlatformSpecificTools.h" + +#include +#include +#include +#include +#include + +namespace comm { + +void NativeSQLiteConnectionManager::attachSession() { + int sessionCreationResult = + sqlite3session_create(dbConnection, "main", &backupLogsSession); + handleSQLiteError(sessionCreationResult, "Failed to create sqlite3 session."); + + static const std::vector tablesToMonitor = { + "drafts", + "messages", + "media", + "threads", + "message_store_threads", + "reports", + "keyservers", + "users"}; + + for (const auto &table : tablesToMonitor) { + int sessionAttachResult = + sqlite3session_attach(backupLogsSession, table.c_str()); + handleSQLiteError( + sessionAttachResult, + "Failed to attach sqlite3 session to " + table + " table."); + } +} + +void NativeSQLiteConnectionManager::detachSession() { + if (!backupLogsSession) { + return; + } + sqlite3session_delete(backupLogsSession); + backupLogsSession = nullptr; +} + +void NativeSQLiteConnectionManager::persistLog( + std::string backupID, + std::string logID, + std::uint8_t *patchsetPtr, + int patchsetSize) { + std::string finalFilePath = + PlatformSpecificTools::getBackupLogFilePath(backupID, logID, false); + std::string tempFilePath = finalFilePath + "_tmp"; + + std::ofstream tempFile( + tempFilePath, std::ofstream::out | std::ofstream::trunc); + + if (!tempFile.is_open()) { + throw std::runtime_error("Failed to open temporary log file."); + } + tempFile.write(reinterpret_cast(patchsetPtr), patchsetSize); + tempFile.close(); + if (std::rename(tempFilePath.c_str(), finalFilePath.c_str())) { + throw std::runtime_error( + "Failed to rename complete log file from temporary path to target " + "path."); + } +} + +NativeSQLiteConnectionManager::NativeSQLiteConnectionManager() + : backupLogsSession(nullptr) { +} + +void NativeSQLiteConnectionManager::setLogsMonitoring(bool enabled) { + if (!backupLogsSession) { + return; + } + sqlite3session_enable(backupLogsSession, enabled); +} + +void NativeSQLiteConnectionManager::initializeConnection( + std::string sqliteFilePath, + std::function on_db_open_callback) { + SQLiteConnectionManager::initializeConnection( + sqliteFilePath, on_db_open_callback); + attachSession(); + setLogsMonitoring(false); +} + +void NativeSQLiteConnectionManager::closeConnection() { + detachSession(); + SQLiteConnectionManager::closeConnectionInternal(); +} + +NativeSQLiteConnectionManager::~NativeSQLiteConnectionManager() { + detachSession(); +} + +bool NativeSQLiteConnectionManager::captureLogs( + std::string backupID, + std::string logID) { + int patchsetSize; + std::uint8_t *patchsetPtr; + int getPatchsetResult = sqlite3session_patchset( + backupLogsSession, &patchsetSize, (void **)&patchsetPtr); + handleSQLiteError(getPatchsetResult, "Failed to get patchset from session."); + + if (!patchsetPtr) { + return false; + } + + if (patchsetSize == 0) { + sqlite3_free(patchsetPtr); + return false; + } + + persistLog(backupID, logID, patchsetPtr, patchsetSize); + sqlite3_free(patchsetPtr); + + // The session is not "zeroed" after capturing log. + // See: https://www.sqlite.org/sessionintro.html + // So we need to delete and recreate session each + // time we capture log. + detachSession(); + attachSession(); + return true; +} +} // namespace comm diff --git a/native/cpp/CommonCpp/DatabaseManagers/SQLiteConnectionManager.h b/native/cpp/CommonCpp/DatabaseManagers/SQLiteConnectionManager.h new file mode 100644 --- /dev/null +++ b/native/cpp/CommonCpp/DatabaseManagers/SQLiteConnectionManager.h @@ -0,0 +1,30 @@ +#pragma once + +#ifndef SQLITE_ENABLE_SESSION +#define SQLITE_ENABLE_SESSION +#endif + +#include +#include +#include + +namespace comm { +class SQLiteConnectionManager { +protected: + sqlite3 *dbConnection; + static void handleSQLiteError( + int errorCode, + const std::string &errorMessagePrefix, + int expectedResultCode = SQLITE_OK); + void closeConnectionInternal(); + +public: + SQLiteConnectionManager(); + sqlite3 *getConnection(); + virtual void initializeConnection( + std::string sqliteFilePath, + std::function on_db_open_callback); + virtual void closeConnection(); + virtual ~SQLiteConnectionManager(); +}; +} // namespace comm diff --git a/native/cpp/CommonCpp/DatabaseManagers/SQLiteConnectionManager.cpp b/native/cpp/CommonCpp/DatabaseManagers/SQLiteConnectionManager.cpp new file mode 100644 --- /dev/null +++ b/native/cpp/CommonCpp/DatabaseManagers/SQLiteConnectionManager.cpp @@ -0,0 +1,56 @@ +#include "SQLiteConnectionManager.h" + +#include +#include +#include +#include + +namespace comm { + +SQLiteConnectionManager::SQLiteConnectionManager() : dbConnection(nullptr) { +} + +sqlite3 *SQLiteConnectionManager::getConnection() { + return dbConnection; +} + +void SQLiteConnectionManager::handleSQLiteError( + int errorCode, + const std::string &errorMessagePrefix, + int expectedResultCode) { + if (errorCode != expectedResultCode) { + throw std::runtime_error( + errorMessagePrefix + " Details: " + sqlite3_errstr(errorCode)); + } +} + +void SQLiteConnectionManager::initializeConnection( + std::string sqliteFilePath, + std::function on_db_open_callback) { + if (dbConnection) { + return; + } + + int connectResult = sqlite3_open(sqliteFilePath.c_str(), &dbConnection); + handleSQLiteError(connectResult, "Failed to open database connection."); + on_db_open_callback(dbConnection); +} + +void SQLiteConnectionManager::closeConnectionInternal() { + if (!dbConnection) { + return; + } + + int closeResult = sqlite3_close(dbConnection); + handleSQLiteError(closeResult, "Failed to close database connection."); + dbConnection = nullptr; +} + +void SQLiteConnectionManager::closeConnection() { + closeConnectionInternal(); +} + +SQLiteConnectionManager::~SQLiteConnectionManager() { + closeConnectionInternal(); +} +} // namespace comm diff --git a/native/cpp/CommonCpp/DatabaseManagers/SQLiteQueryExecutor.h b/native/cpp/CommonCpp/DatabaseManagers/SQLiteQueryExecutor.h --- a/native/cpp/CommonCpp/DatabaseManagers/SQLiteQueryExecutor.h +++ b/native/cpp/CommonCpp/DatabaseManagers/SQLiteQueryExecutor.h @@ -2,6 +2,7 @@ #include "../CryptoTools/Persist.h" #include "DatabaseQueryExecutor.h" +#include "NativeSQLiteConnectionManager.h" #include "entities/Draft.h" #include "entities/KeyserverInfo.h" #include "entities/UserInfo.h" @@ -19,10 +20,12 @@ static std::once_flag initialized; static int sqlcipherEncryptionKeySize; static std::string secureStoreEncryptionKeyID; - static sqlite3 *dbConnection; #ifndef EMSCRIPTEN + static NativeSQLiteConnectionManager connectionManager; static void assign_encryption_key(); +#else + static SQLiteConnectionManager connectionManager; #endif public: @@ -109,6 +112,7 @@ static void clearSensitiveData(); static void initialize(std::string &databasePath); void createMainCompaction(std::string backupID) const override; + void captureBackupLogs() const override; #endif }; diff --git a/native/cpp/CommonCpp/DatabaseManagers/SQLiteQueryExecutor.cpp b/native/cpp/CommonCpp/DatabaseManagers/SQLiteQueryExecutor.cpp --- a/native/cpp/CommonCpp/DatabaseManagers/SQLiteQueryExecutor.cpp +++ b/native/cpp/CommonCpp/DatabaseManagers/SQLiteQueryExecutor.cpp @@ -12,6 +12,7 @@ #ifndef EMSCRIPTEN #include "CommSecureStore.h" #include "PlatformSpecificTools.h" +#include "StaffUtils.h" #endif #define ACCOUNT_ID 1 @@ -24,7 +25,12 @@ int SQLiteQueryExecutor::sqlcipherEncryptionKeySize = 64; std::string SQLiteQueryExecutor::secureStoreEncryptionKeyID = "comm.encryptionKey"; -sqlite3 *SQLiteQueryExecutor::dbConnection = nullptr; + +#ifndef EMSCRIPTEN +NativeSQLiteConnectionManager SQLiteQueryExecutor::connectionManager; +#else +SQLiteConnectionManager SQLiteQueryExecutor::connectionManager; +#endif bool create_table(sqlite3 *db, std::string query, std::string tableName) { char *error; @@ -650,28 +656,6 @@ return false; } -void trace_queries(sqlite3 *db) { - int error_code = sqlite3_trace_v2( - db, - SQLITE_TRACE_PROFILE, - [](unsigned, void *, void *preparedStatement, void *) { - sqlite3_stmt *statement = (sqlite3_stmt *)preparedStatement; - char *sql = sqlite3_expanded_sql(statement); - if (sql != nullptr) { - std::string sqlStr(sql); - // TODO: send logs to backup here - } - return 0; - }, - NULL); - if (error_code != SQLITE_OK) { - std::ostringstream error_message; - error_message << "Failed to set trace callback, error code: " << error_code; - throw std::system_error( - ECANCELED, std::generic_category(), error_message.str()); - } -} - // We don't want to run `PRAGMA key = ...;` // on main web database. The context is here: // https://linear.app/comm/issue/ENG-6398/issues-with-sqlcipher-on-web @@ -679,7 +663,6 @@ #ifndef EMSCRIPTEN set_encryption_key(db); #endif - trace_queries(db); } // This is a temporary solution. In future we want to keep @@ -981,6 +964,13 @@ SQLiteQueryExecutor::SQLiteQueryExecutor() { SQLiteQueryExecutor::migrate(); +#ifndef EMSCRIPTEN + std::string currentBackupID = this->getMetadata("backupID"); + if (!StaffUtils::isStaffRelease() || !currentBackupID.size()) { + return; + } + SQLiteQueryExecutor::connectionManager.setLogsMonitoring(true); +#endif } SQLiteQueryExecutor::SQLiteQueryExecutor(std::string sqliteFilePath) { @@ -989,31 +979,16 @@ } sqlite3 *SQLiteQueryExecutor::getConnection() { - if (SQLiteQueryExecutor::dbConnection) { - return SQLiteQueryExecutor::dbConnection; - } - - int connectResult = sqlite3_open( - SQLiteQueryExecutor::sqliteFilePath.c_str(), - &SQLiteQueryExecutor::dbConnection); - - if (connectResult != SQLITE_OK) { - std::stringstream error_message; - error_message << "Failed to open database connection. Details: " - << sqlite3_errstr(connectResult) << std::endl; - throw std::runtime_error(error_message.str()); + if (SQLiteQueryExecutor::connectionManager.getConnection()) { + return SQLiteQueryExecutor::connectionManager.getConnection(); } - - default_on_db_open_callback(SQLiteQueryExecutor::dbConnection); - return SQLiteQueryExecutor::dbConnection; + SQLiteQueryExecutor::connectionManager.initializeConnection( + SQLiteQueryExecutor::sqliteFilePath, default_on_db_open_callback); + return SQLiteQueryExecutor::connectionManager.getConnection(); } void SQLiteQueryExecutor::closeConnection() { - if (!SQLiteQueryExecutor::dbConnection) { - return; - } - sqlite3_close(SQLiteQueryExecutor::dbConnection); - SQLiteQueryExecutor::dbConnection = nullptr; + SQLiteQueryExecutor::connectionManager.closeConnection(); } SQLiteQueryExecutor::~SQLiteQueryExecutor() { @@ -1774,6 +1749,12 @@ finalAttachmentsPath, "Failed to rename complete temporary attachments file to final " "attachments file."); + + this->setMetadata("backupID", backupID); + this->clearMetadata("logID"); + if (StaffUtils::isStaffRelease()) { + SQLiteQueryExecutor::connectionManager.setLogsMonitoring(true); + } } void SQLiteQueryExecutor::assign_encryption_key() { @@ -1783,6 +1764,25 @@ SQLiteQueryExecutor::secureStoreEncryptionKeyID, encryptionKey); SQLiteQueryExecutor::encryptionKey = encryptionKey; } + +void SQLiteQueryExecutor::captureBackupLogs() const { + std::string backupID = this->getMetadata("backupID"); + if (!backupID.size()) { + return; + } + + std::string logID = this->getMetadata("logID"); + if (!logID.size()) { + logID = "0"; + } + + bool newLogCreated = + SQLiteQueryExecutor::connectionManager.captureLogs(backupID, logID); + if (!newLogCreated) { + return; + } + this->setMetadata("logID", std::to_string(std::stoi(logID) + 1)); +} #endif void SQLiteQueryExecutor::restoreFromMainCompaction( diff --git a/native/ios/Comm.xcodeproj/project.pbxproj b/native/ios/Comm.xcodeproj/project.pbxproj --- a/native/ios/Comm.xcodeproj/project.pbxproj +++ b/native/ios/Comm.xcodeproj/project.pbxproj @@ -71,6 +71,7 @@ CB3C0A3B2A125C8F009BD4DA /* NotificationsCryptoModule.cpp in Sources */ = {isa = PBXBuildFile; fileRef = CB24361729A39A2500FEC4E1 /* NotificationsCryptoModule.cpp */; }; CB3C621127CE4A320054F24C /* Logger.mm in Sources */ = {isa = PBXBuildFile; fileRef = 71CA4A63262DA8E500835C89 /* Logger.mm */; }; CB3C621227CE65030054F24C /* CommSecureStoreIOSWrapper.mm in Sources */ = {isa = PBXBuildFile; fileRef = 71142A7626C2650A0039DCBD /* CommSecureStoreIOSWrapper.mm */; }; + CB3CCB012B72470700793640 /* NativeSQLiteConnectionManager.cpp in Sources */ = {isa = PBXBuildFile; fileRef = CB3CCB002B7246F400793640 /* NativeSQLiteConnectionManager.cpp */; }; CB4821A927CFB153001AB7E1 /* WorkerThread.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 718DE99C2653D41C00365824 /* WorkerThread.cpp */; }; CB4821AA27CFB153001AB7E1 /* Tools.mm in Sources */ = {isa = PBXBuildFile; fileRef = 71CA4AEB262F236100835C89 /* Tools.mm */; }; CB4821AC27CFB17C001AB7E1 /* Session.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 71BF5B6F26B3FF0900EDE27D /* Session.cpp */; }; @@ -81,6 +82,7 @@ CB7EF17E295C674300B17035 /* CommIOSNotifications.mm in Sources */ = {isa = PBXBuildFile; fileRef = CB7EF17D295C5D1800B17035 /* CommIOSNotifications.mm */; }; CB7EF180295C674300B17035 /* CommIOSNotificationsBridgeQueue.mm in Sources */ = {isa = PBXBuildFile; fileRef = CB7EF17B295C580500B17035 /* CommIOSNotificationsBridgeQueue.mm */; }; CB90951F29534B32002F2A7F /* CommSecureStore.mm in Sources */ = {isa = PBXBuildFile; fileRef = 71D4D7CB26C50B1000FCDBCD /* CommSecureStore.mm */; }; + CBA5F8852B6979F7005BE700 /* SQLiteConnectionManager.cpp in Sources */ = {isa = PBXBuildFile; fileRef = CBA5F8842B6979ED005BE700 /* SQLiteConnectionManager.cpp */; }; CBAAA4702B459181007599DA /* BackupOperationsExecutor.cpp in Sources */ = {isa = PBXBuildFile; fileRef = CBAAA46E2B459181007599DA /* BackupOperationsExecutor.cpp */; }; CBCA09062A8E0E7400F75B3E /* StaffUtils.cpp in Sources */ = {isa = PBXBuildFile; fileRef = CBCA09052A8E0E6B00F75B3E /* StaffUtils.cpp */; }; CBCA09072A8E0E7D00F75B3E /* StaffUtils.cpp in Sources */ = {isa = PBXBuildFile; fileRef = CBCA09052A8E0E6B00F75B3E /* StaffUtils.cpp */; }; @@ -275,6 +277,8 @@ CB38F2BE286C6C980010535C /* DeleteEntryMessageSpec.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DeleteEntryMessageSpec.h; path = PersistentStorageUtilities/MessageOperationsUtilities/MessageSpecs/DeleteEntryMessageSpec.h; sourceTree = ""; }; CB38F2BF286C6C980010535C /* UpdateRelationshipMessageSpec.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = UpdateRelationshipMessageSpec.h; path = PersistentStorageUtilities/MessageOperationsUtilities/MessageSpecs/UpdateRelationshipMessageSpec.h; sourceTree = ""; }; CB3C621327CE66540054F24C /* libEXSecureStore.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; path = libEXSecureStore.a; sourceTree = BUILT_PRODUCTS_DIR; }; + CB3CCAFF2B7246F400793640 /* NativeSQLiteConnectionManager.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = NativeSQLiteConnectionManager.h; sourceTree = ""; }; + CB3CCB002B7246F400793640 /* NativeSQLiteConnectionManager.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = NativeSQLiteConnectionManager.cpp; sourceTree = ""; }; CB74AB1B2B2AFF6E00CBB494 /* CommServicesAuthMetadataEmitter.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = CommServicesAuthMetadataEmitter.mm; path = Comm/CommServicesAuthMetadataEmitter.mm; sourceTree = ""; }; CB74AB1E2B2B0C0900CBB494 /* RustCSAMetadataEmitter.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = RustCSAMetadataEmitter.cpp; sourceTree = ""; }; CB74AB1F2B2B0C0900CBB494 /* RustCSAMetadataEmitter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RustCSAMetadataEmitter.h; sourceTree = ""; }; @@ -282,6 +286,8 @@ CB7EF17C295C580500B17035 /* CommIOSNotificationsBridgeQueue.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = CommIOSNotificationsBridgeQueue.h; path = Comm/CommIOSNotifications/CommIOSNotificationsBridgeQueue.h; sourceTree = ""; }; CB7EF17D295C5D1800B17035 /* CommIOSNotifications.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; name = CommIOSNotifications.mm; path = Comm/CommIOSNotifications/CommIOSNotifications.mm; sourceTree = ""; }; CB90951929531663002F2A7F /* CommIOSNotifications.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CommIOSNotifications.h; path = Comm/CommIOSNotifications/CommIOSNotifications.h; sourceTree = ""; }; + CBA5F8832B6979ED005BE700 /* SQLiteConnectionManager.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SQLiteConnectionManager.h; sourceTree = ""; }; + CBA5F8842B6979ED005BE700 /* SQLiteConnectionManager.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = SQLiteConnectionManager.cpp; sourceTree = ""; }; CBA784382B28AC4300E9F419 /* CommServicesAuthMetadataEmitter.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CommServicesAuthMetadataEmitter.h; sourceTree = ""; }; CBAAA46E2B459181007599DA /* BackupOperationsExecutor.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = BackupOperationsExecutor.cpp; path = PersistentStorageUtilities/BackupOperationsUtilities/BackupOperationsExecutor.cpp; sourceTree = ""; }; CBAAA46F2B459181007599DA /* BackupOperationsExecutor.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = BackupOperationsExecutor.h; path = PersistentStorageUtilities/BackupOperationsUtilities/BackupOperationsExecutor.h; sourceTree = ""; }; @@ -474,6 +480,10 @@ 71BE843F2636A944002849D2 /* DatabaseManagers */ = { isa = PBXGroup; children = ( + CB3CCB002B7246F400793640 /* NativeSQLiteConnectionManager.cpp */, + CB3CCAFF2B7246F400793640 /* NativeSQLiteConnectionManager.h */, + CBA5F8842B6979ED005BE700 /* SQLiteConnectionManager.cpp */, + CBA5F8832B6979ED005BE700 /* SQLiteConnectionManager.h */, 8E86A6D229537EBB000BBE7D /* DatabaseManager.cpp */, 71BE84402636A944002849D2 /* DatabaseQueryExecutor.h */, 71BE84412636A944002849D2 /* SQLiteQueryExecutor.cpp */, @@ -1097,6 +1107,8 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + CB3CCB012B72470700793640 /* NativeSQLiteConnectionManager.cpp in Sources */, + CBA5F8852B6979F7005BE700 /* SQLiteConnectionManager.cpp in Sources */, CB01F0C42B67F3A10089E1F9 /* SQLiteStatementWrapper.cpp in Sources */, CB01F0C22B67EF5A0089E1F9 /* SQLiteDataConverters.cpp in Sources */, CBAAA4702B459181007599DA /* BackupOperationsExecutor.cpp in Sources */, diff --git a/web/database/_generated/comm_query_executor.wasm b/web/database/_generated/comm_query_executor.wasm index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 GIT binary patch literal 0 Hc$@