diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index fec6c0eda..fbca16af0 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -106,6 +106,8 @@ set(LINPHONE_CXX_OBJECTS_PRIVATE_HEADER_FILES core/platform-helpers/platform-helpers.h db/abstract/abstract-db-p.h db/abstract/abstract-db.h + db/internal/db-transaction.h + db/internal/statements.h db/main-db-chat-message-key.h db/main-db-event-key.h db/main-db-key-p.h @@ -225,6 +227,7 @@ set(LINPHONE_CXX_OBJECTS_SOURCE_FILES core/paths/paths.cpp core/platform-helpers/platform-helpers.cpp db/abstract/abstract-db.cpp + db/internal/statements.cpp db/main-db-chat-message-key.cpp db/main-db-event-key.cpp db/main-db-key.cpp @@ -284,24 +287,15 @@ elseif (UNIX) list(APPEND LINPHONE_CXX_OBJECTS_PRIVATE_HEADER_FILES core/paths/paths-linux.h) endif () -set(LINPHONE_CXX_OBJECTS_INCLUDE_DIRS ${BELR_INCLUDE_DIRS} ${LIBXSD_INCLUDE_DIRS}) +set(LINPHONE_CXX_OBJECTS_INCLUDE_DIRS + ${BELR_INCLUDE_DIRS} + ${LIBXSD_INCLUDE_DIRS} + ${SOCI_INCLUDE_DIRS} + ${SOCI_MYSQL_INCLUDES} +) set(LINPHONE_CXX_OBJECTS_DEFINITIONS "-DLIBLINPHONE_EXPORTS") set(LINPHONE_CXX_OBJECTS_INCLUDE_DIRS ${BELR_INCLUDE_DIRS}) -if (SOCI_FOUND) - list(APPEND LINPHONE_CXX_OBJECTS_INCLUDE_DIRS ${SOCI_INCLUDE_DIRS} ${SOCI_MYSQL_INCLUDES}) - add_definitions(-DSOCI_ENABLED) - - list(APPEND LINPHONE_CXX_OBJECTS_PRIVATE_HEADER_FILES - db/internal/db-exception-handler.h - db/internal/statements.h - ) - - list(APPEND LINPHONE_CXX_OBJECTS_SOURCE_FILES - db/internal/statements.cpp - ) -endif () - set(LINPHONE_PRIVATE_HEADER_FILES) foreach (header ${LINPHONE_CXX_OBJECTS_PRIVATE_HEADER_FILES}) list(APPEND LINPHONE_PRIVATE_HEADER_FILES "${CMAKE_CURRENT_SOURCE_DIR}/${header}") diff --git a/src/address/address.h b/src/address/address.h index cccca9ac8..f92300277 100644 --- a/src/address/address.h +++ b/src/address/address.h @@ -20,6 +20,8 @@ #ifndef _L_ADDRESS_H_ #define _L_ADDRESS_H_ +#include + #include "enums.h" #include "object/clonable-object.h" @@ -107,6 +109,11 @@ private: L_DECLARE_PRIVATE(Address); }; +inline std::ostream &operator<< (std::ostream &os, const Address &address) { + os << "Address(" << address.asString() << ")"; + return os; +} + LINPHONE_END_NAMESPACE #endif // ifndef _L_ADDRESS_H_ diff --git a/src/address/identity-address.h b/src/address/identity-address.h index 58afd9ff4..2e39b959b 100644 --- a/src/address/identity-address.h +++ b/src/address/identity-address.h @@ -20,6 +20,8 @@ #ifndef _L_IDENTITY_ADDRESS_H_ #define _L_IDENTITY_ADDRESS_H_ +#include + #include "object/clonable-object.h" // ============================================================================= @@ -65,6 +67,11 @@ private: L_DECLARE_PRIVATE(IdentityAddress); }; +inline std::ostream &operator<< (std::ostream &os, const IdentityAddress &identityAddress) { + os << "IdentityAddress(" << identityAddress.asString() << ")"; + return os; +} + LINPHONE_END_NAMESPACE #endif // ifndef _L_IDENTITY_ADDRESS_H_ diff --git a/src/chat/chat-room/chat-room-id.h b/src/chat/chat-room/chat-room-id.h index c82dd0da4..1751a6820 100644 --- a/src/chat/chat-room/chat-room-id.h +++ b/src/chat/chat-room/chat-room-id.h @@ -50,6 +50,11 @@ private: L_DECLARE_PRIVATE(ChatRoomId); }; +inline std::ostream &operator<< (std::ostream &os, const ChatRoomId &chatRoomId) { + os << "ChatRoomId(" << chatRoomId.getPeerAddress() << ", local=" << chatRoomId.getLocalAddress() << ")"; + return os; +} + LINPHONE_END_NAMESPACE // Add map key support. diff --git a/src/core/core-chat-room.cpp b/src/core/core-chat-room.cpp index 6def1428b..1084d48e6 100644 --- a/src/core/core-chat-room.cpp +++ b/src/core/core-chat-room.cpp @@ -162,10 +162,8 @@ shared_ptr Core::findChatRoom (const ChatRoomId &chatRoomId) c if (it != d->chatRoomsById.cend()) return it->second; - lInfo() << "Unable to find chat room in RAM: (peer=" << - chatRoomId.getPeerAddress().asString() << ", local=" << chatRoomId.getLocalAddress().asString() << ")."; - - return shared_ptr(); + lInfo() << "Unable to find chat room in RAM: " << chatRoomId << "."; + return nullptr; } list> Core::findChatRooms (const IdentityAddress &peerAddress) const { diff --git a/src/db/abstract/abstract-db-p.h b/src/db/abstract/abstract-db-p.h index d596d7b8d..4064c5408 100644 --- a/src/db/abstract/abstract-db-p.h +++ b/src/db/abstract/abstract-db-p.h @@ -30,8 +30,6 @@ LINPHONE_BEGIN_NAMESPACE class AbstractDbPrivate : public ObjectPrivate { public: - AbstractDbPrivate () = default; - DbSession dbSession; private: diff --git a/src/db/abstract/abstract-db.cpp b/src/db/abstract/abstract-db.cpp index bf56b954d..18531439a 100644 --- a/src/db/abstract/abstract-db.cpp +++ b/src/db/abstract/abstract-db.cpp @@ -21,9 +21,9 @@ #include #endif // ifdef __APPLE__ -#if defined(SOCI_ENABLED) && (TARGET_OS_IPHONE || defined(__ANDROID__)) +#if (TARGET_OS_IPHONE || defined(__ANDROID__)) #include -#endif // if defined(SOCI_ENABLED) && (TARGET_OS_IPHONE || defined(__ANDROID__)) +#endif // if (TARGET_OS_IPHONE || defined(__ANDROID__)) #include "abstract-db-p.h" #include "logger/logger.h" @@ -34,22 +34,20 @@ using namespace std; LINPHONE_BEGIN_NAMESPACE -#if defined(SOCI_ENABLED) && (TARGET_OS_IPHONE || defined(__ANDROID__)) +#if (TARGET_OS_IPHONE || defined(__ANDROID__)) // Force static sqlite3 linking for IOS and Android. extern "C" void register_factory_sqlite3(); static void sqlite3Log (void *, int iErrCode, const char *zMsg) { lInfo() << "[sqlite3][" << iErrCode << "]" << zMsg; } -#endif // if defined(SOCI_ENABLED) && (TARGET_OS_IPHONE || defined(__ANDROID__)) +#endif // if (TARGET_OS_IPHONE || defined(__ANDROID__)) void AbstractDbPrivate::safeInit () { - #ifdef SOCI_ENABLED - L_Q(); - dbSession.enableForeignKeys(false); - q->init(); - dbSession.enableForeignKeys(true); - #endif // ifdef SOCI_ENABLED + L_Q(); + dbSession.enableForeignKeys(false); + q->init(); + dbSession.enableForeignKeys(true); } AbstractDb::AbstractDb (AbstractDbPrivate &p) : Object(p) {} @@ -57,7 +55,7 @@ AbstractDb::AbstractDb (AbstractDbPrivate &p) : Object(p) {} bool AbstractDb::connect (Backend backend, const string ¶meters) { L_D(); - #if defined(SOCI_ENABLED) && (TARGET_OS_IPHONE || defined(__ANDROID__)) + #if (TARGET_OS_IPHONE || defined(__ANDROID__)) if (backend == Sqlite3) { static bool registered = false; if (!registered) { @@ -66,7 +64,7 @@ bool AbstractDb::connect (Backend backend, const string ¶meters) { sqlite3_config(SQLITE_CONFIG_LOG, sqlite3Log, nullptr); } } - #endif // if defined(SOCI_ENABLED) && (TARGET_OS_IPHONE || defined(__ANDROID__)) + #endif // if (TARGET_OS_IPHONE || defined(__ANDROID__)) d->backend = backend; d->dbSession = DbSession( @@ -99,30 +97,28 @@ bool AbstractDb::forceReconnect () { return false; } - #ifdef SOCI_ENABLED - constexpr int retryCount = 2; - lInfo() << "Trying sql backend reconnect..."; + constexpr int retryCount = 2; + lInfo() << "Trying sql backend reconnect..."; - try { - for (int i = 0; i < retryCount; ++i) { - try { - lInfo() << "Reconnect... Try: " << i; - d->dbSession.getBackendSession()->reconnect(); // Equivalent to close and connect. - d->safeInit(); - lInfo() << "Database reconnection successful!"; - return true; - } catch (const soci::soci_error &e) { - if (e.get_error_category() != soci::soci_error::connection_error) - throw e; - } + try { + for (int i = 0; i < retryCount; ++i) { + try { + lInfo() << "Reconnect... Try: " << i; + d->dbSession.getBackendSession()->reconnect(); // Equivalent to close and connect. + d->safeInit(); + lInfo() << "Database reconnection successful!"; + return true; + } catch (const soci::soci_error &e) { + if (e.get_error_category() != soci::soci_error::connection_error) + throw e; } - } catch (const exception &e) { - lError() << "Unable to reconnect: `" << e.what() << "`."; - return false; } + } catch (const exception &e) { + lError() << "Unable to reconnect: `" << e.what() << "`."; + return false; + } - lError() << "Database reconnection failed!"; - #endif // ifdef SOCI_ENABLED + lError() << "Database reconnection failed!"; return false; } diff --git a/src/db/abstract/abstract-db.h b/src/db/abstract/abstract-db.h index 1d612b58b..a6b401dd8 100644 --- a/src/db/abstract/abstract-db.h +++ b/src/db/abstract/abstract-db.h @@ -28,7 +28,7 @@ LINPHONE_BEGIN_NAMESPACE class AbstractDbPrivate; -class LINPHONE_PUBLIC AbstractDb : public Object { +class AbstractDb : public Object { public: enum Backend { Mysql, diff --git a/src/db/internal/db-exception-handler.h b/src/db/internal/db-transaction.h similarity index 82% rename from src/db/internal/db-exception-handler.h rename to src/db/internal/db-transaction.h index 74084a7ac..dbb57fa12 100644 --- a/src/db/internal/db-exception-handler.h +++ b/src/db/internal/db-transaction.h @@ -1,5 +1,5 @@ /* - * db-exception-handler.h + * db-transaction.h * Copyright (C) 2010-2018 Belledonne Communications SARL * * This program is free software; you can redistribute it and/or @@ -17,20 +17,18 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -#ifndef _L_DB_EXCEPTION_HANDLER_H_ -#define _L_DB_EXCEPTION_HANDLER_H_ - -#include +#ifndef _L_DB_TRANSACTION_H_ +#define _L_DB_TRANSACTION_H_ #include "db/main-db-p.h" #include "logger/logger.h" // ============================================================================= -#define L_DB_EXCEPTION_HANDLER_C(CONTEXT) \ - LinphonePrivate::DbExceptionHandlerInfo().set(__func__, CONTEXT) * [&](SmartTransaction &tr) +#define L_DB_TRANSACTION_C(CONTEXT) \ + LinphonePrivate::DbTransactionInfo().set(__func__, CONTEXT) * [&](SmartTransaction &tr) -#define L_DB_EXCEPTION_HANDLER L_DB_EXCEPTION_HANDLER_C(this) +#define L_DB_TRANSACTION L_DB_TRANSACTION_C(this) LINPHONE_BEGIN_NAMESPACE @@ -68,8 +66,8 @@ private: L_DISABLE_COPY(SmartTransaction); }; -struct DbExceptionHandlerInfo { - DbExceptionHandlerInfo &set (const char *_name, const MainDb *_mainDb) { +struct DbTransactionInfo { + DbTransactionInfo &set (const char *_name, const MainDb *_mainDb) { name = _name; mainDb = const_cast(_mainDb); return *this; @@ -80,7 +78,7 @@ struct DbExceptionHandlerInfo { }; template -class DbExceptionHandler { +class DbTransaction { using InternalReturnType = typename std::remove_reference< decltype(std::declval()(std::declval())) >::type; @@ -92,7 +90,7 @@ public: InternalReturnType >::type; - DbExceptionHandler (DbExceptionHandlerInfo &info, Function &&function) : mFunction(std::move(function)) { + DbTransaction (DbTransactionInfo &info, Function &&function) : mFunction(std::move(function)) { MainDb *mainDb = info.mainDb; const char *name = info.name; soci::session *session = mainDb->getPrivate()->dbSession.getBackendSession(); @@ -122,7 +120,7 @@ public: } } - DbExceptionHandler (DbExceptionHandler &&dbExceptionHandler) : mFunction(std::move(dbExceptionHandler.mFunction)) {} + DbTransaction (DbTransaction &&DbTransaction) : mFunction(std::move(DbTransaction.mFunction)) {} operator ReturnType () const { return mResult; @@ -170,14 +168,14 @@ private: Function mFunction; ReturnType mResult{}; - L_DISABLE_COPY(DbExceptionHandler); + L_DISABLE_COPY(DbTransaction); }; template -typename DbExceptionHandler::ReturnType operator* (DbExceptionHandlerInfo &info, Function &&function) { - return DbExceptionHandler(info, std::forward(function)); +typename DbTransaction::ReturnType operator* (DbTransactionInfo &info, Function &&function) { + return DbTransaction(info, std::forward(function)); } LINPHONE_END_NAMESPACE -#endif // ifndef _L_DB_EXCEPTION_HANDLER_H_ +#endif // ifndef _L_DB_TRANSACTION_H_ diff --git a/src/db/internal/statements.cpp b/src/db/internal/statements.cpp index b0bf05cc8..6b6754228 100644 --- a/src/db/internal/statements.cpp +++ b/src/db/internal/statements.cpp @@ -50,42 +50,11 @@ namespace Statements { const char *mSql[2]; }; - // --------------------------------------------------------------------------- - // Create statements. - // --------------------------------------------------------------------------- - - constexpr AbstractStatement create[CreateCount] = { - [CreateConferenceEventView] = { { - Backend::Sqlite3, R"( - CREATE VIEW IF NOT EXISTS conference_event_view AS - SELECT id, type, creation_time, chat_room_id, from_sip_address_id, to_sip_address_id, time, imdn_message_id, state, direction, is_secured, notify_id, device_sip_address_id, participant_sip_address_id, subject - FROM event - LEFT JOIN conference_event ON conference_event.event_id = event.id - LEFT JOIN conference_chat_message_event ON conference_chat_message_event.event_id = event.id - LEFT JOIN conference_notified_event ON conference_notified_event.event_id = event.id - LEFT JOIN conference_participant_device_event ON conference_participant_device_event.event_id = event.id - LEFT JOIN conference_participant_event ON conference_participant_event.event_id = event.id - LEFT JOIN conference_subject_event ON conference_subject_event.event_id = event.id - )" }, { - Backend::Mysql, R"( - CREATE OR REPLACE VIEW conference_event_view AS - SELECT id, type, creation_time, chat_room_id, from_sip_address_id, to_sip_address_id, time, imdn_message_id, state, direction, is_secured, notify_id, device_sip_address_id, participant_sip_address_id, subject - FROM event - LEFT JOIN conference_event ON conference_event.event_id = event.id - LEFT JOIN conference_chat_message_event ON conference_chat_message_event.event_id = event.id - LEFT JOIN conference_notified_event ON conference_notified_event.event_id = event.id - LEFT JOIN conference_participant_device_event ON conference_participant_device_event.event_id = event.id - LEFT JOIN conference_participant_event ON conference_participant_event.event_id = event.id - LEFT JOIN conference_subject_event ON conference_subject_event.event_id = event.id - )" - } } - }; - // --------------------------------------------------------------------------- // Select statements. // --------------------------------------------------------------------------- - constexpr AbstractStatement select[SelectCount] = { + constexpr const char *select[SelectCount] = { [SelectSipAddressId] = R"( SELECT id FROM sip_address @@ -111,6 +80,19 @@ namespace Statements { AND participant_b_sip_address_id IN (:3, :4) )", + [SelectConferenceEvent] = R"( + SELECT conference_event_view.id AS event_id, type, conference_event_view.creation_time, from_sip_address.value, to_sip_address.value, time, imdn_message_id, state, direction, is_secured, notify_id, device_sip_address.value, participant_sip_address.value, conference_event_view.subject, peer_sip_address.value, local_sip_address.value + FROM conference_event_view + JOIN chat_room ON chat_room.id = chat_room_id + JOIN sip_address AS peer_sip_address ON peer_sip_address.id = peer_sip_address_id + JOIN sip_address AS local_sip_address ON local_sip_address.id = local_sip_address_id + LEFT JOIN sip_address AS from_sip_address ON from_sip_address.id = from_sip_address_id + LEFT JOIN sip_address AS to_sip_address ON to_sip_address.id = to_sip_address_id + LEFT JOIN sip_address AS device_sip_address ON device_sip_address.id = device_sip_address_id + LEFT JOIN sip_address AS participant_sip_address ON participant_sip_address.id = participant_sip_address_id + WHERE event_id = :1 + )", + [SelectConferenceEvents] = R"( SELECT conference_event_view.id AS event_id, type, creation_time, from_sip_address.value, to_sip_address.value, time, imdn_message_id, state, direction, is_secured, notify_id, device_sip_address.value, participant_sip_address.value, subject FROM conference_event_view @@ -138,12 +120,8 @@ namespace Statements { // Getters. // --------------------------------------------------------------------------- - const char *get (Create createStmt, AbstractDb::Backend backend) { - return createStmt >= Create::CreateCount ? nullptr : create[createStmt].get(backend); - } - - const char *get (Select selectStmt, AbstractDb::Backend backend) { - return selectStmt >= Select::SelectCount ? nullptr : select[selectStmt].get(backend); + const char *get (Select selectStmt) { + return selectStmt >= Select::SelectCount ? nullptr : select[selectStmt]; } const char *get (Insert insertStmt, AbstractDb::Backend backend) { diff --git a/src/db/internal/statements.h b/src/db/internal/statements.h index bc14a1b92..4f518ccad 100644 --- a/src/db/internal/statements.h +++ b/src/db/internal/statements.h @@ -27,16 +27,12 @@ LINPHONE_BEGIN_NAMESPACE namespace Statements { - enum Create { - CreateConferenceEventView, - CreateCount - }; - enum Select { SelectSipAddressId, SelectChatRoomId, SelectChatRoomParticipantId, SelectOneToOneChatRoomId, + SelectConferenceEvent, SelectConferenceEvents, SelectCount }; @@ -46,8 +42,7 @@ namespace Statements { InsertCount }; - const char *get (Create createStmt, AbstractDb::Backend backend); - const char *get (Select selectStmt, AbstractDb::Backend backend); + const char *get (Select selectStmt); const char *get (Insert insertStmt, AbstractDb::Backend backend); } diff --git a/src/db/main-db-p.h b/src/db/main-db-p.h index 4c9e263ab..8a8a52ad1 100644 --- a/src/db/main-db-p.h +++ b/src/db/main-db-p.h @@ -22,6 +22,8 @@ #include +#include "linphone/utils/utils.h" + #include "abstract/abstract-db-p.h" #include "event-log/event-log.h" #include "main-db.h" @@ -38,12 +40,18 @@ public: mutable std::unordered_map> storageIdToChatMessage; private: + // --------------------------------------------------------------------------- + // Misc helpers. + // --------------------------------------------------------------------------- + + std::shared_ptr findChatRoom (const ChatRoomId &chatRoomId) const; + // --------------------------------------------------------------------------- // Low level API. // --------------------------------------------------------------------------- long long insertSipAddress (const std::string &sipAddress); - void insertContent (long long messageEventId, const Content &content); + void insertContent (long long chatMessageId, const Content &content); long long insertContentType (const std::string &contentType); long long insertOrUpdateImportedBasicChatRoom ( long long peerSipAddressId, @@ -53,7 +61,7 @@ private: long long insertChatRoom (const std::shared_ptr &chatRoom); long long insertChatRoomParticipant (long long chatRoomId, long long participantSipAddressId, bool isAdmin); void insertChatRoomParticipantDevice (long long participantId, long long participantDeviceSipAddressId); - void insertChatMessageParticipant (long long messageEventId, long long sipAddressId, int state); + void insertChatMessageParticipant (long long chatMessageId, long long sipAddressId, int state); long long selectSipAddressId (const std::string &sipAddress) const; long long selectChatRoomId (long long peerSipAddressId, long long localSipAddressId) const; @@ -61,7 +69,7 @@ private: long long selectChatRoomParticipantId (long long chatRoomId, long long participantSipAddressId) const; long long selectOneToOneChatRoomId (long long sipAddressIdA, long long sipAddressIdB) const; - void deleteContents (long long messageEventId); + void deleteContents (long long chatMessageId); void deleteChatRoomParticipant (long long chatRoomId, long long participantSipAddressId); void deleteChatRoomParticipantDevice (long long participantId, long long participantDeviceSipAddressId); @@ -69,68 +77,65 @@ private: // Events API. // --------------------------------------------------------------------------- + long long getConferenceEventIdFromRow (const soci::row &row) const { + return dbSession.resolveId(row, -1); + } + + time_t getConferenceEventCreationTimeFromRow (const soci::row &row) const { + return Utils::getTmAsTimeT(row.get(2)); + } + + unsigned int getConferenceEventNotifyIdFromRow (const soci::row &row) const { + L_Q(); + return q->getBackend() == MainDb::Backend::Mysql + ? row.get(10, 0) + : static_cast(row.get(10, 0)); + } + std::shared_ptr selectGenericConferenceEvent ( - long long eventId, - EventLog::Type type, - time_t creationTime, - const ChatRoomId &chatRoomId + const std::shared_ptr &chatRoom, + const soci::row &row + ) const; + + std::shared_ptr selectGenericConferenceNotifiedEvent ( + const ChatRoomId &chatRoomId, + const soci::row &row ) const; std::shared_ptr selectConferenceEvent ( - long long eventId, + const ChatRoomId &chatRoomId, EventLog::Type type, - time_t creationTime, - const ChatRoomId &chatRoomId + const soci::row &row ) const; std::shared_ptr selectConferenceCallEvent ( - long long eventId, + const ChatRoomId &chatRoomId, EventLog::Type type, - time_t creationTime, - const ChatRoomId &chatRoomId + const soci::row &row ) const; std::shared_ptr selectConferenceChatMessageEvent ( - long long eventId, + const std::shared_ptr &chatRoom, EventLog::Type type, - time_t creationTime, - const ChatRoomId &chatRoomId - ) const; - - // TODO: Remove me. Workaround to increase fetch performance. - std::shared_ptr selectConferenceChatMessageEvent ( - long long eventId, - EventLog::Type type, - time_t creationTime, - std::shared_ptr &chatRoom, - const std::string &fromSipAddress, - const std::string &toSipAddress, - const tm &messageTime, - const std::string &imdnMessageId, - int state, - int direction, - int isSecured + const soci::row &row ) const; std::shared_ptr selectConferenceParticipantEvent ( - long long eventId, + const ChatRoomId &chatRoomId, EventLog::Type type, - time_t creationTime, - const ChatRoomId &chatRoomId + const soci::row &row ) const; std::shared_ptr selectConferenceParticipantDeviceEvent ( - long long eventId, + const ChatRoomId &chatRoomId, EventLog::Type type, - time_t creationTime, - const ChatRoomId &chatRoomId + const soci::row &row ) const; std::shared_ptr selectConferenceSubjectEvent ( - long long eventId, + const ChatRoomId &chatRoomId, EventLog::Type type, - time_t creationTime, - const ChatRoomId &chatRoomId + const soci::row &row ) const; long long insertEvent (const std::shared_ptr &eventLog); diff --git a/src/db/main-db.cpp b/src/db/main-db.cpp index a3f11b66f..45b80c128 100644 --- a/src/db/main-db.cpp +++ b/src/db/main-db.cpp @@ -20,7 +20,6 @@ #include #include "linphone/utils/algorithm.h" -#include "linphone/utils/utils.h" #include "linphone/utils/static-string.h" #include "chat/chat-message/chat-message-p.h" @@ -28,19 +27,13 @@ #include "chat/chat-room/client-group-chat-room.h" #include "chat/chat-room/server-group-chat-room.h" #include "conference/participant-p.h" -#include "content/content-type.h" -#include "content/content.h" #include "core/core-p.h" #include "event-log/event-log-p.h" #include "event-log/events.h" -#include "logger/logger.h" #include "main-db-key-p.h" -#include "main-db-p.h" -#ifdef SOCI_ENABLED - #include "internal/db-exception-handler.h" - #include "internal/statements.h" -#endif // ifdef SOCI_ENABLED +#include "internal/db-transaction.h" +#include "internal/statements.h" // ============================================================================= @@ -88,11 +81,38 @@ namespace { constexpr int LegacyMessageColIsSecured = 14; } +// ----------------------------------------------------------------------------- +// soci helpers. // ----------------------------------------------------------------------------- -MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), CoreAccessor(core) {} +static inline vector blobToVector (soci::blob &in) { + size_t len = in.get_len(); + if (!len) + return vector(); + vector out(len); + in.read(0, &out[0], len); + return out; +} -#ifdef SOCI_ENABLED +static inline string blobToString (soci::blob &in) { + vector out = blobToVector(in); + return string(out.begin(), out.end()); +} + +static constexpr string &blobToString (string &in) { + return in; +} + +template +static T getValueFromRow (const soci::row &row, int index, bool &isNull) { + isNull = false; + + if (row.get_indicator(size_t(index)) == soci::i_null) { + isNull = true; + return T(); + } + return row.get(size_t(index)); +} // ----------------------------------------------------------------------------- // Event filter tools. @@ -202,45 +222,39 @@ static string buildSqlEventFilter ( return sql; } +// ----------------------------------------------------------------------------- +// Misc helpers. // ----------------------------------------------------------------------------- -static inline vector blobToVector (soci::blob &in) { - size_t len = in.get_len(); - if (!len) - return vector(); - vector out(len); - in.read(0, &out[0], len); - return out; +shared_ptr MainDbPrivate::findChatRoom (const ChatRoomId &chatRoomId) const { + L_Q(); + shared_ptr chatRoom = q->getCore()->findChatRoom(chatRoomId); + if (!chatRoom) + lError() << "Unable to find chat room: " << chatRoomId << "."; + return chatRoom; } -static inline string blobToString (soci::blob &in) { - vector out = blobToVector(in); - return string(out.begin(), out.end()); -} - -static constexpr string &blobToString (string &in) { - return in; -} +// ----------------------------------------------------------------------------- +// Low level API. +// ----------------------------------------------------------------------------- long long MainDbPrivate::insertSipAddress (const string &sipAddress) { - soci::session *session = dbSession.getBackendSession(); - long long id = selectSipAddressId(sipAddress); if (id >= 0) return id; lInfo() << "Insert new sip address in database: `" << sipAddress << "`."; - *session << "INSERT INTO sip_address (value) VALUES (:sipAddress)", soci::use(sipAddress); + *dbSession.getBackendSession() << "INSERT INTO sip_address (value) VALUES (:sipAddress)", soci::use(sipAddress); return dbSession.getLastInsertId(); } -void MainDbPrivate::insertContent (long long eventId, const Content &content) { +void MainDbPrivate::insertContent (long long chatMessageId, const Content &content) { soci::session *session = dbSession.getBackendSession(); const long long &contentTypeId = insertContentType(content.getContentType().asString()); const string &body = content.getBodyAsString(); *session << "INSERT INTO chat_message_content (event_id, content_type_id, body) VALUES" - " (:eventId, :contentTypeId, :body)", soci::use(eventId), soci::use(contentTypeId), + " (:chatMessageId, :contentTypeId, :body)", soci::use(chatMessageId), soci::use(contentTypeId), soci::use(body); const long long &chatMessageContentId = dbSession.getLastInsertId(); @@ -249,7 +263,7 @@ void MainDbPrivate::insertContent (long long eventId, const Content &content) { const string &name = fileContent.getFileName(); const size_t &size = fileContent.getFileSize(); const string &path = fileContent.getFilePath(); - *session << "INSERT INTO chat_message_file_content (chat_message_content_id, name, size, path) VALUES " + *session << "INSERT INTO chat_message_file_content (chat_message_content_id, name, size, path) VALUES" " (:chatMessageContentId, :name, :size, :path)", soci::use(chatMessageContentId), soci::use(name), soci::use(size), soci::use(path); } @@ -287,7 +301,7 @@ long long MainDbPrivate::insertOrUpdateImportedBasicChatRoom ( return id; } - static const int capabilities = ChatRoom::CapabilitiesMask( + constexpr int capabilities = ChatRoom::CapabilitiesMask( { ChatRoom::Capabilities::Basic, ChatRoom::Capabilities::Migratable } ); lInfo() << "Insert new chat room in database: (peer=" << peerSipAddressId << @@ -302,30 +316,25 @@ long long MainDbPrivate::insertOrUpdateImportedBasicChatRoom ( } long long MainDbPrivate::insertChatRoom (const shared_ptr &chatRoom) { - soci::session *session = dbSession.getBackendSession(); - const ChatRoomId &chatRoomId = chatRoom->getChatRoomId(); const long long &peerSipAddressId = insertSipAddress(chatRoomId.getPeerAddress().asString()); const long long &localSipAddressId = insertSipAddress(chatRoomId.getLocalAddress().asString()); long long id = selectChatRoomId(peerSipAddressId, localSipAddressId); - if (id >= 0) { - lError() << "Unable to insert chat room (it already exists): (peer=" << peerSipAddressId << - ", local=" << localSipAddressId << ")."; + if (id >= 0) return id; - } - lInfo() << "Insert new chat room in database: (peer=" << peerSipAddressId << - ", local=" << localSipAddressId << ")."; + lInfo() << "Insert new chat room in database: " << chatRoomId << "."; const tm &creationTime = Utils::getTimeTAsTm(chatRoom->getCreationTime()); const tm &lastUpdateTime = Utils::getTimeTAsTm(chatRoom->getLastUpdateTime()); + // Remove capabilities like `Proxy`. const int &capabilities = chatRoom->getCapabilities() & ~ChatRoom::CapabilitiesMask(ChatRoom::Capabilities::Proxy); const string &subject = chatRoom->getSubject(); const int &flags = chatRoom->hasBeenLeft(); - *session << "INSERT INTO chat_room (" + *dbSession.getBackendSession() << "INSERT INTO chat_room (" " peer_sip_address_id, local_sip_address_id, creation_time, last_update_time, capabilities, subject, flags" ") VALUES (:peerSipAddressId, :localSipAddressId, :creationTime, :lastUpdateTime, :capabilities, :subject, :flags)", soci::use(peerSipAddressId), soci::use(localSipAddressId), soci::use(creationTime), soci::use(lastUpdateTime), @@ -374,8 +383,6 @@ long long MainDbPrivate::insertChatRoomParticipant ( return id; } - lInfo() << "Insert new chat room participant in database: `" << participantSipAddressId << - "` (isAdmin=" << isAdmin << ")."; *session << "INSERT INTO chat_room_participant (chat_room_id, participant_sip_address_id, is_admin)" " VALUES (:chatRoomId, :participantSipAddressId, :isAdmin)", soci::use(chatRoomId), soci::use(participantSipAddressId), soci::use(static_cast(isAdmin)); @@ -396,42 +403,36 @@ void MainDbPrivate::insertChatRoomParticipantDevice ( if (count) return; - lInfo() << "Insert new chat room participant device in database: `" << participantDeviceSipAddressId << "`."; *session << "INSERT INTO chat_room_participant_device (chat_room_participant_id, participant_device_sip_address_id)" " VALUES (:participantId, :participantDeviceSipAddressId)", soci::use(participantId), soci::use(participantDeviceSipAddressId); } -void MainDbPrivate::insertChatMessageParticipant (long long eventId, long long sipAddressId, int state) { - if (state != static_cast(ChatMessage::State::Displayed)) { - soci::session *session = dbSession.getBackendSession(); - *session << "INSERT INTO chat_message_participant (event_id, participant_sip_address_id, state)" - " VALUES (:eventId, :sipAddressId, :state)", - soci::use(eventId), soci::use(sipAddressId), soci::use(state); - } +void MainDbPrivate::insertChatMessageParticipant (long long chatMessageId, long long sipAddressId, int state) { + if (state != static_cast(ChatMessage::State::Displayed)) + *dbSession.getBackendSession() << + "INSERT INTO chat_message_participant (event_id, participant_sip_address_id, state)" + " VALUES (:chatMessageId, :sipAddressId, :state)", + soci::use(chatMessageId), soci::use(sipAddressId), soci::use(state); } // ----------------------------------------------------------------------------- long long MainDbPrivate::selectSipAddressId (const string &sipAddress) const { - L_Q(); - long long id; soci::session *session = dbSession.getBackendSession(); - *session << Statements::get(Statements::SelectSipAddressId, q->getBackend()), + *session << Statements::get(Statements::SelectSipAddressId), soci::use(sipAddress), soci::into(id); return session->got_data() ? id : -1; } long long MainDbPrivate::selectChatRoomId (long long peerSipAddressId, long long localSipAddressId) const { - L_Q(); - long long id; soci::session *session = dbSession.getBackendSession(); - *session << Statements::get(Statements::SelectChatRoomId, q->getBackend()), + *session << Statements::get(Statements::SelectChatRoomId), soci::use(peerSipAddressId), soci::use(localSipAddressId), soci::into(id); return session->got_data() ? id : -1; @@ -450,24 +451,20 @@ long long MainDbPrivate::selectChatRoomId (const ChatRoomId &chatRoomId) const { } long long MainDbPrivate::selectChatRoomParticipantId (long long chatRoomId, long long participantSipAddressId) const { - L_Q(); - long long id; soci::session *session = dbSession.getBackendSession(); - *session << Statements::get(Statements::SelectChatRoomParticipantId, q->getBackend()), + *session << Statements::get(Statements::SelectChatRoomParticipantId), soci::use(chatRoomId), soci::use(participantSipAddressId), soci::into(id); return session->got_data() ? id : -1; } long long MainDbPrivate::selectOneToOneChatRoomId (long long sipAddressIdA, long long sipAddressIdB) const { - L_Q(); - long long id; soci::session *session = dbSession.getBackendSession(); - *session << Statements::get(Statements::SelectOneToOneChatRoomId, q->getBackend()), + *session << Statements::get(Statements::SelectOneToOneChatRoomId), soci::use(sipAddressIdA), soci::use(sipAddressIdB), soci::use(sipAddressIdA), soci::use(sipAddressIdB), soci::into(id); @@ -476,15 +473,14 @@ long long MainDbPrivate::selectOneToOneChatRoomId (long long sipAddressIdA, long // ----------------------------------------------------------------------------- -void MainDbPrivate::deleteContents (long long messageEventId) { - soci::session *session = dbSession.getBackendSession(); - *session << "DELETE FROM chat_message_content WHERE event_id = :messageEventId", soci::use(messageEventId); +void MainDbPrivate::deleteContents (long long chatMessageId) { + *dbSession.getBackendSession() << "DELETE FROM chat_message_content WHERE event_id = :chatMessageId", + soci::use(chatMessageId); } void MainDbPrivate::deleteChatRoomParticipant (long long chatRoomId, long long participantSipAddressId) { - soci::session *session = dbSession.getBackendSession(); - *session << "DELETE FROM chat_room_participant" - " WHERE chat_room_id = :chatRoomId AND participant_sip_address_id = :participantSipAddressId", + *dbSession.getBackendSession() << "DELETE FROM chat_room_participant" + " WHERE chat_room_id = :chatRoomId AND participant_sip_address_id = :participantSipAddressId", soci::use(chatRoomId), soci::use(participantSipAddressId); } @@ -492,55 +488,74 @@ void MainDbPrivate::deleteChatRoomParticipantDevice ( long long participantId, long long participantDeviceSipAddressId ) { - soci::session *session = dbSession.getBackendSession(); - *session << "DELETE FROM chat_room_participant_device" - " WHERE chat_room_participant_id = :participantId" - " AND participant_device_sip_address_id = :participantDeviceSipAddressId", + *dbSession.getBackendSession() << "DELETE FROM chat_room_participant_device" + " WHERE chat_room_participant_id = :participantId" + " AND participant_device_sip_address_id = :participantDeviceSipAddressId", soci::use(participantId), soci::use(participantDeviceSipAddressId); } +// ----------------------------------------------------------------------------- +// Events API. // ----------------------------------------------------------------------------- shared_ptr MainDbPrivate::selectGenericConferenceEvent ( - long long eventId, - EventLog::Type type, - time_t creationTime, - const ChatRoomId &chatRoomId + const shared_ptr &chatRoom, + const soci::row &row ) const { - shared_ptr eventLog; + EventLog::Type type = EventLog::Type(row.get(1)); + if (type == EventLog::Type::ConferenceChatMessage) { + long long eventId = getConferenceEventIdFromRow(row); + shared_ptr eventLog = getEventFromCache(eventId); + if (!eventLog) { + eventLog = selectConferenceChatMessageEvent(chatRoom, type, row); + if (eventLog) + cache(eventLog, eventId); + } + return eventLog; + } + return selectGenericConferenceNotifiedEvent(chatRoom->getChatRoomId(), row); +} + +shared_ptr MainDbPrivate::selectGenericConferenceNotifiedEvent ( + const ChatRoomId &chatRoomId, + const soci::row &row +) const { + long long eventId = getConferenceEventIdFromRow(row); + shared_ptr eventLog = getEventFromCache(eventId); + if (eventLog) + return eventLog; + + EventLog::Type type = EventLog::Type(row.get(1)); switch (type) { case EventLog::Type::None: + case EventLog::Type::ConferenceChatMessage: return nullptr; case EventLog::Type::ConferenceCreated: case EventLog::Type::ConferenceTerminated: - eventLog = selectConferenceEvent(eventId, type, creationTime, chatRoomId); + eventLog = selectConferenceEvent(chatRoomId, type, row); break; case EventLog::Type::ConferenceCallStart: case EventLog::Type::ConferenceCallEnd: - eventLog = selectConferenceCallEvent(eventId, type, creationTime, chatRoomId); - break; - - case EventLog::Type::ConferenceChatMessage: - eventLog = selectConferenceChatMessageEvent(eventId, type, creationTime, chatRoomId); + eventLog = selectConferenceCallEvent(chatRoomId, type, row); break; case EventLog::Type::ConferenceParticipantAdded: case EventLog::Type::ConferenceParticipantRemoved: case EventLog::Type::ConferenceParticipantSetAdmin: case EventLog::Type::ConferenceParticipantUnsetAdmin: - eventLog = selectConferenceParticipantEvent(eventId, type, creationTime, chatRoomId); + eventLog = selectConferenceParticipantEvent(chatRoomId, type, row); break; case EventLog::Type::ConferenceParticipantDeviceAdded: case EventLog::Type::ConferenceParticipantDeviceRemoved: - eventLog = selectConferenceParticipantDeviceEvent(eventId, type, creationTime, chatRoomId); + eventLog = selectConferenceParticipantDeviceEvent(chatRoomId, type, row); break; case EventLog::Type::ConferenceSubjectChanged: - eventLog = selectConferenceSubjectEvent(eventId, type, creationTime, chatRoomId); + eventLog = selectConferenceSubjectEvent(chatRoomId, type, row); break; } @@ -551,130 +566,48 @@ shared_ptr MainDbPrivate::selectGenericConferenceEvent ( } shared_ptr MainDbPrivate::selectConferenceEvent ( - long long, + const ChatRoomId &chatRoomId, EventLog::Type type, - time_t creationTime, - const ChatRoomId &chatRoomId + const soci::row &row ) const { return make_shared( type, - creationTime, + getConferenceEventCreationTimeFromRow(row), chatRoomId ); } shared_ptr MainDbPrivate::selectConferenceCallEvent ( - long long eventId, + const ChatRoomId &chatRoomId, EventLog::Type type, - time_t creationTime, - const ChatRoomId &chatRoomId + const soci::row &row ) const { // TODO. return nullptr; } -template -static void fetchContentAppData (soci::session *session, Content &content, long long contentId, T &data) { - static const string query = "SELECT name, data FROM chat_message_content_app_data" - " WHERE chat_message_content_id = :contentId"; - - string name; - soci::statement statement = (session->prepare << query, soci::use(contentId), soci::into(name), soci::into(data)); - statement.execute(); - while (statement.fetch()) - content.setAppData(name, blobToString(data)); -} - shared_ptr MainDbPrivate::selectConferenceChatMessageEvent ( - long long eventId, + const shared_ptr &chatRoom, EventLog::Type type, - time_t creationTime, - const ChatRoomId &chatRoomId -) const { - L_Q(); - - shared_ptr core = q->getCore(); - shared_ptr chatRoom = core->findChatRoom(chatRoomId); - if (!chatRoom) { - lError() << "Unable to find chat room storage id of (peer=" + - chatRoomId.getPeerAddress().asString() + - ", local=" + chatRoomId.getLocalAddress().asString() + "`)."; - return nullptr; - } - - shared_ptr chatMessage = getChatMessageFromCache(eventId); - if (!chatMessage) { - string fromSipAddress; - string toSipAddress; - - tm messageTime; - - string imdnMessageId; - - int state; - int direction; - int isSecured; - - soci::session *session = dbSession.getBackendSession(); - *session << "SELECT from_sip_address.value, to_sip_address.value, time, imdn_message_id, state, direction, is_secured" - " FROM event, conference_chat_message_event, sip_address AS from_sip_address, sip_address AS to_sip_address" - " WHERE event_id = :eventId" - " AND event_id = event.id" - " AND from_sip_address_id = from_sip_address.id" - " AND to_sip_address_id = to_sip_address.id", soci::into(fromSipAddress), soci::into(toSipAddress), - soci::into(messageTime), soci::into(imdnMessageId), soci::into(state), soci::into(direction), - soci::into(isSecured), soci::use(eventId); - - return selectConferenceChatMessageEvent ( - eventId, - type, - creationTime, - chatRoom, - fromSipAddress, - toSipAddress, - messageTime, - imdnMessageId, - state, - direction, - isSecured - ); - } - - return make_shared( - creationTime, - chatMessage - ); -} - -shared_ptr MainDbPrivate::selectConferenceChatMessageEvent ( - long long eventId, - EventLog::Type type, - time_t creationTime, - shared_ptr &chatRoom, - const string &fromSipAddress, - const string &toSipAddress, - const tm &messageTime, - const string &imdnMessageId, - int state, - int direction, - int isSecured + const soci::row &row ) const { + long long eventId = getConferenceEventIdFromRow(row); shared_ptr chatMessage = getChatMessageFromCache(eventId); if (!chatMessage) { chatMessage = shared_ptr(new ChatMessage( chatRoom, - ChatMessage::Direction(direction) + ChatMessage::Direction(row.get(8)) )); - chatMessage->setIsSecured(bool(isSecured)); + chatMessage->setIsSecured(bool(row.get(9))); ChatMessagePrivate *dChatMessage = chatMessage->getPrivate(); - dChatMessage->setState(ChatMessage::State(state), true); + dChatMessage->setState(ChatMessage::State(row.get(7)), true); - dChatMessage->forceFromAddress(IdentityAddress(fromSipAddress)); - dChatMessage->forceToAddress(IdentityAddress(toSipAddress)); + dChatMessage->forceFromAddress(IdentityAddress(row.get(3))); + dChatMessage->forceToAddress(IdentityAddress(row.get(4))); - dChatMessage->setTime(Utils::getTmAsTimeT(messageTime)); - dChatMessage->setImdnMessageId(imdnMessageId); + dChatMessage->setTime(Utils::getTmAsTimeT(row.get(5))); + dChatMessage->setImdnMessageId(row.get(6)); dChatMessage->markContentsAsNotLoaded(); dChatMessage->setIsReadOnly(true); @@ -683,102 +616,60 @@ shared_ptr MainDbPrivate::selectConferenceChatMessageEvent ( } return make_shared( - creationTime, + getConferenceEventCreationTimeFromRow(row), chatMessage ); } shared_ptr MainDbPrivate::selectConferenceParticipantEvent ( - long long eventId, + const ChatRoomId &chatRoomId, EventLog::Type type, - time_t creationTime, - const ChatRoomId &chatRoomId + const soci::row &row ) const { - unsigned int notifyId; - string participantAddress; - - soci::session *session = dbSession.getBackendSession(); - *session << "SELECT notify_id, participant_address.value" - " FROM conference_notified_event, conference_participant_event, sip_address as participant_address" - " WHERE conference_participant_event.event_id = :eventId" - " AND conference_notified_event.event_id = conference_participant_event.event_id" - " AND participant_address.id = participant_sip_address_id", - soci::into(notifyId), soci::into(participantAddress), soci::use(eventId); - return make_shared( type, - creationTime, + getConferenceEventCreationTimeFromRow(row), chatRoomId, - notifyId, - IdentityAddress(participantAddress) + getConferenceEventNotifyIdFromRow(row), + IdentityAddress(row.get(12)) ); } shared_ptr MainDbPrivate::selectConferenceParticipantDeviceEvent ( - long long eventId, + const ChatRoomId &chatRoomId, EventLog::Type type, - time_t creationTime, - const ChatRoomId &chatRoomId + const soci::row &row ) const { - unsigned int notifyId; - string participantAddress; - string deviceAddress; - - soci::session *session = dbSession.getBackendSession(); - *session << "SELECT notify_id, participant_address.value, device_address.value" - " FROM conference_notified_event, conference_participant_event, conference_participant_device_event," - " sip_address AS participant_address, sip_address AS device_address" - " WHERE conference_participant_device_event.event_id = :eventId" - " AND conference_participant_event.event_id = conference_participant_device_event.event_id" - " AND conference_notified_event.event_id = conference_participant_event.event_id" - " AND participant_address.id = participant_sip_address_id" - " AND device_address.id = device_sip_address_id", - soci::into(notifyId), soci::into(participantAddress), soci::into(deviceAddress), soci::use(eventId); - return make_shared( type, - creationTime, + getConferenceEventCreationTimeFromRow(row), chatRoomId, - notifyId, - IdentityAddress(participantAddress), - IdentityAddress(deviceAddress) + getConferenceEventNotifyIdFromRow(row), + IdentityAddress(row.get(12)), + IdentityAddress(row.get(11)) ); } shared_ptr MainDbPrivate::selectConferenceSubjectEvent ( - long long eventId, + const ChatRoomId &chatRoomId, EventLog::Type type, - time_t creationTime, - const ChatRoomId &chatRoomId + const soci::row &row ) const { - unsigned int notifyId; - string subject; - - soci::session *session = dbSession.getBackendSession(); - *session << "SELECT notify_id, subject" - " FROM conference_notified_event, conference_subject_event" - " WHERE conference_subject_event.event_id = :eventId" - " AND conference_notified_event.event_id = conference_subject_event.event_id", - soci::into(notifyId), soci::into(subject), soci::use(eventId); - return make_shared( - creationTime, + getConferenceEventCreationTimeFromRow(row), chatRoomId, - notifyId, - subject + getConferenceEventNotifyIdFromRow(row), + row.get(13) ); } // ----------------------------------------------------------------------------- long long MainDbPrivate::insertEvent (const shared_ptr &eventLog) { - soci::session *session = dbSession.getBackendSession(); - const int &type = int(eventLog->getType()); const tm &creationTime = Utils::getTimeTAsTm(eventLog->getCreationTime()); - *session << "INSERT INTO event (type, creation_time) VALUES (:type, :creationTime)", - soci::use(type), - soci::use(creationTime); + *dbSession.getBackendSession() << "INSERT INTO event (type, creation_time) VALUES (:type, :creationTime)", + soci::use(type), soci::use(creationTime); return dbSession.getLastInsertId(); } @@ -792,9 +683,7 @@ long long MainDbPrivate::insertConferenceEvent (const shared_ptr &even // A conference event can be inserted in database only if chat room exists. // Otherwise it's an error. const ChatRoomId &chatRoomId = conferenceEvent->getChatRoomId(); - lError() << "Unable to find chat room storage id of (peer=" + - chatRoomId.getPeerAddress().asString() + - ", local=" + chatRoomId.getLocalAddress().asString() + "`)."; + lError() << "Unable to find chat room storage id of: " << chatRoomId << "."; } else { eventId = insertEvent(eventLog); @@ -823,19 +712,11 @@ long long MainDbPrivate::insertConferenceCallEvent (const shared_ptr & } long long MainDbPrivate::insertConferenceChatMessageEvent (const shared_ptr &eventLog) { - shared_ptr chatMessage = static_pointer_cast(eventLog)->getChatMessage(); - shared_ptr chatRoom = chatMessage->getChatRoom(); - if (!chatRoom) { - lError() << "Unable to get a valid chat room. It was removed from database."; - return -1; - } - const long long &eventId = insertConferenceEvent(eventLog); if (eventId < 0) return -1; - soci::session *session = dbSession.getBackendSession(); - + shared_ptr chatMessage = static_pointer_cast(eventLog)->getChatMessage(); const long long &fromSipAddressId = insertSipAddress(chatMessage->getFromAddress().asString()); const long long &toSipAddressId = insertSipAddress(chatMessage->getToAddress().asString()); const tm &messageTime = Utils::getTimeTAsTm(chatMessage->getTime()); @@ -844,7 +725,7 @@ long long MainDbPrivate::insertConferenceChatMessageEvent (const shared_ptrgetImdnMessageId(); const int &isSecured = chatMessage->isSecured() ? 1 : 0; - *session << "INSERT INTO conference_chat_message_event (" + *dbSession.getBackendSession() << "INSERT INTO conference_chat_message_event (" " event_id, from_sip_address_id, to_sip_address_id," " time, state, direction, imdn_message_id, is_secured" ") VALUES (" @@ -857,7 +738,7 @@ long long MainDbPrivate::insertConferenceChatMessageEvent (const shared_ptrgetContents()) insertContent(eventId, *content); - for (const auto &participant : chatRoom->getParticipants()) { + for (const auto &participant : chatMessage->getChatRoom()->getParticipants()) { const long long &participantSipAddressId = selectSipAddressId(participant->getAddress().asString()); insertChatMessageParticipant(eventId, participantSipAddressId, state); } @@ -867,20 +748,14 @@ long long MainDbPrivate::insertConferenceChatMessageEvent (const shared_ptr &eventLog) { shared_ptr chatMessage = static_pointer_cast(eventLog)->getChatMessage(); - shared_ptr chatRoom = chatMessage->getChatRoom(); - if (!chatRoom) { - lError() << "Unable to get a valid chat room. It was removed from database."; - return; - } const EventLogPrivate *dEventLog = eventLog->getPrivate(); MainDbKeyPrivate *dEventKey = static_cast(dEventLog->dbKey).getPrivate(); const long long &eventId = dEventKey->storageId; - soci::session *session = dbSession.getBackendSession(); const int &state = int(chatMessage->getState()); const string &imdnMessageId = chatMessage->getImdnMessageId(); - *session << "UPDATE conference_chat_message_event SET state = :state, imdn_message_id = :imdnMessageId" + *dbSession.getBackendSession() << "UPDATE conference_chat_message_event SET state = :state, imdn_message_id = :imdnMessageId" " WHERE event_id = :eventId", soci::use(state), soci::use(imdnMessageId), soci::use(eventId); @@ -925,9 +800,8 @@ long long MainDbPrivate::insertConferenceParticipantEvent ( participantEvent->getParticipantAddress().asString() ); - soci::session *session = dbSession.getBackendSession(); - *session << "INSERT INTO conference_participant_event (event_id, participant_sip_address_id)" - " VALUES (:eventId, :participantAddressId)", soci::use(eventId), soci::use(participantAddressId); + *dbSession.getBackendSession() << "INSERT INTO conference_participant_event (event_id, participant_sip_address_id)" + " VALUES (:eventId, :participantAddressId)", soci::use(eventId), soci::use(participantAddressId); bool isAdmin = eventLog->getType() == EventLog::Type::ConferenceParticipantSetAdmin; switch (eventLog->getType()) { @@ -969,15 +843,14 @@ long long MainDbPrivate::insertConferenceParticipantDeviceEvent (const shared_pt const long long &participantId = selectChatRoomParticipantId(chatRoomId, participantAddressId); if (participantId < 0) { lError() << "Unable to find valid participant id in database with chat room id = " << chatRoomId << - " and participant address id = " << participantId; + " and participant address id = " << participantAddressId; return -1; } const long long &deviceAddressId = insertSipAddress( participantDeviceEvent->getDeviceAddress().asString() ); - soci::session *session = dbSession.getBackendSession(); - *session << "INSERT INTO conference_participant_device_event (event_id, device_sip_address_id)" + *dbSession.getBackendSession() << "INSERT INTO conference_participant_device_event (event_id, device_sip_address_id)" " VALUES (:eventId, :deviceAddressId)", soci::use(eventId), soci::use(deviceAddressId); switch (eventLog->getType()) { @@ -1014,6 +887,8 @@ long long MainDbPrivate::insertConferenceSubjectEvent (const shared_ptr MainDbPrivate::getEventFromCache (long long storageId) const { @@ -1022,7 +897,6 @@ shared_ptr MainDbPrivate::getEventFromCache (long long storageId) cons return nullptr; shared_ptr eventLog = it->second.lock(); - // Must exist. If not, implementation bug. L_ASSERT(eventLog); return eventLog; } @@ -1033,7 +907,6 @@ shared_ptr MainDbPrivate::getChatMessageFromCache (long long storag return nullptr; shared_ptr chatMessage = it->second.lock(); - // Must exist. If not, implementation bug. L_ASSERT(chatMessage); return chatMessage; } @@ -1059,8 +932,7 @@ void MainDbPrivate::cache (const shared_ptr &chatMessage, long long } void MainDbPrivate::invalidConferenceEventsFromQuery (const string &query, long long chatRoomId) { - soci::session *session = dbSession.getBackendSession(); - soci::rowset rows = (session->prepare << query, soci::use(chatRoomId)); + soci::rowset rows = (dbSession.getBackendSession()->prepare << query, soci::use(chatRoomId)); for (const auto &row : rows) { long long eventId = dbSession.resolveId(row, 0); shared_ptr eventLog = getEventFromCache(eventId); @@ -1069,7 +941,6 @@ void MainDbPrivate::invalidConferenceEventsFromQuery (const string &query, long L_ASSERT(dEventLog->dbKey.isValid()); dEventLog->dbKey = MainDbEventKey(); } - // TODO: Try to add a better code here... shared_ptr chatMessage = getChatMessageFromCache(eventId); if (chatMessage) { const ChatMessagePrivate *dChatMessage = chatMessage->getPrivate(); @@ -1079,6 +950,8 @@ void MainDbPrivate::invalidConferenceEventsFromQuery (const string &query, long } } +// ----------------------------------------------------------------------------- +// Versions. // ----------------------------------------------------------------------------- unsigned int MainDbPrivate::getModuleVersion (const string &name) { @@ -1103,14 +976,14 @@ void MainDbPrivate::updateSchema () { soci::session *session = dbSession.getBackendSession(); unsigned int version = getModuleVersion("events"); - if (version < makeVersion(1, 0, 1)) { + if (version < makeVersion(1, 0, 1)) *session << "ALTER TABLE chat_room_participant_device ADD COLUMN state TINYINT UNSIGNED DEFAULT 0"; - } } +// ----------------------------------------------------------------------------- +// Import. // ----------------------------------------------------------------------------- -// NOTE: Legacy supports only sqlite. static inline bool checkLegacyTableExists (soci::session &session, const string &name) { session << "SELECT name FROM sqlite_master WHERE type='table' AND name = :name", soci::use(name); return session.got_data() > 0; @@ -1124,22 +997,9 @@ static inline bool checkLegacyHistoryTableExists (soci::session &session) { return checkLegacyTableExists(session, "history"); } -template -static T getValueFromRow (const soci::row &row, int index, bool &isNull) { - isNull = false; - - if (row.get_indicator(size_t(index)) == soci::i_null){ - isNull = true; - return T(); - } - return row.get(size_t(index)); -} - -// ----------------------------------------------------------------------------- - void MainDbPrivate::importLegacyFriends (DbSession &inDbSession) { L_Q(); - L_DB_EXCEPTION_HANDLER_C(q) { + L_DB_TRANSACTION_C(q) { if (getModuleVersion("legacy-friends-import") >= makeVersion(1, 0, 0)) return; updateModuleVersion("legacy-friends-import", ModuleVersionLegacyFriendsImport); @@ -1211,10 +1071,8 @@ void MainDbPrivate::importLegacyFriends (DbSession &inDbSession) { void MainDbPrivate::importLegacyHistory (DbSession &inDbSession) { L_Q(); - L_DB_EXCEPTION_HANDLER_C(q) { - - unsigned int version = getModuleVersion("legacy-history-import"); - if (version >= makeVersion(1, 0, 0)) + L_DB_TRANSACTION_C(q) { + if (getModuleVersion("legacy-history-import") >= makeVersion(1, 0, 0)) return; updateModuleVersion("legacy-history-import", ModuleVersionLegacyHistoryImport); @@ -1299,7 +1157,7 @@ void MainDbPrivate::importLegacyHistory (DbSession &inDbSession) { const int &isSecured = message.get(LegacyMessageColIsSecured, 0); *session << "INSERT INTO conference_event (event_id, chat_room_id)" - " VALUES (:eventId, :chatRoomId)", soci::use(eventId), soci::use(chatRoomId); + " VALUES (:eventId, :chatRoomId)", soci::use(eventId), soci::use(chatRoomId); *session << "INSERT INTO conference_chat_message_event (" " event_id, from_sip_address_id, to_sip_address_id," @@ -1322,7 +1180,9 @@ void MainDbPrivate::importLegacyHistory (DbSession &inDbSession) { }; } -// ----------------------------------------------------------------------------- +// ============================================================================= + +MainDb::MainDb (const shared_ptr &core) : AbstractDb(*new MainDbPrivate), CoreAccessor(core) {} void MainDb::init () { L_D(); @@ -1338,13 +1198,6 @@ void MainDb::init () { auto timestampType = bind(&DbSession::timestampType, &d->dbSession); auto varcharPrimaryKeyStr = bind(&DbSession::varcharPrimaryKeyStr, &d->dbSession, _1); - auto createTableSanitizer = [](const char *statement) { - // TODO. - string sanitized = statement; - return sanitized; - }; - - // TODO: Migrate all statements in statements.cpp. *session << "CREATE TABLE IF NOT EXISTS sip_address (" " id" + primaryKeyStr("BIGINT UNSIGNED") + "," @@ -1661,8 +1514,23 @@ void MainDb::init () { " ON DELETE CASCADE" ") " + charset; - for (int i = 0; i < int(Statements::CreateCount); ++i) - *session << createTableSanitizer(Statements::get(static_cast(i), backend)); + { + string query; + if (getBackend() == Backend::Mysql) + query = "CREATE OR REPLACE VIEW conference_event_view AS"; + else + query = "CREATE VIEW IF NOT EXISTS conference_event_view AS"; + + *session << query + + " SELECT id, type, creation_time, chat_room_id, from_sip_address_id, to_sip_address_id, time, imdn_message_id, state, direction, is_secured, notify_id, device_sip_address_id, participant_sip_address_id, subject" + " FROM event" + " LEFT JOIN conference_event ON conference_event.event_id = event.id" + " LEFT JOIN conference_chat_message_event ON conference_chat_message_event.event_id = event.id" + " LEFT JOIN conference_notified_event ON conference_notified_event.event_id = event.id" + " LEFT JOIN conference_participant_device_event ON conference_participant_device_event.event_id = event.id" + " LEFT JOIN conference_participant_event ON conference_participant_event.event_id = event.id" + " LEFT JOIN conference_subject_event ON conference_subject_event.event_id = event.id"; + } *session << "CREATE TABLE IF NOT EXISTS db_module_version (" @@ -1697,16 +1565,15 @@ void MainDb::init () { } bool MainDb::addEvent (const shared_ptr &eventLog) { - const EventLogPrivate *dEventLog = eventLog->getPrivate(); - if (dEventLog->dbKey.isValid()) { + if (eventLog->getPrivate()->dbKey.isValid()) { lWarning() << "Unable to add an event twice!!!"; return false; } - return L_DB_EXCEPTION_HANDLER { + return L_DB_TRANSACTION { L_D(); - long long storageId = 0; + long long eventId = -1; EventLog::Type type = eventLog->getType(); switch (type) { @@ -1715,41 +1582,41 @@ bool MainDb::addEvent (const shared_ptr &eventLog) { case EventLog::Type::ConferenceCreated: case EventLog::Type::ConferenceTerminated: - storageId = d->insertConferenceEvent(eventLog); + eventId = d->insertConferenceEvent(eventLog); break; case EventLog::Type::ConferenceCallStart: case EventLog::Type::ConferenceCallEnd: - storageId = d->insertConferenceCallEvent(eventLog); + eventId = d->insertConferenceCallEvent(eventLog); break; case EventLog::Type::ConferenceChatMessage: - storageId = d->insertConferenceChatMessageEvent(eventLog); + eventId = d->insertConferenceChatMessageEvent(eventLog); break; case EventLog::Type::ConferenceParticipantAdded: case EventLog::Type::ConferenceParticipantRemoved: case EventLog::Type::ConferenceParticipantSetAdmin: case EventLog::Type::ConferenceParticipantUnsetAdmin: - storageId = d->insertConferenceParticipantEvent(eventLog); + eventId = d->insertConferenceParticipantEvent(eventLog); break; case EventLog::Type::ConferenceParticipantDeviceAdded: case EventLog::Type::ConferenceParticipantDeviceRemoved: - storageId = d->insertConferenceParticipantDeviceEvent(eventLog); + eventId = d->insertConferenceParticipantDeviceEvent(eventLog); break; case EventLog::Type::ConferenceSubjectChanged: - storageId = d->insertConferenceSubjectEvent(eventLog); + eventId = d->insertConferenceSubjectEvent(eventLog); break; } - if (storageId >= 0) { + if (eventId >= 0) { tr.commit(); - d->cache(eventLog, storageId); + d->cache(eventLog, eventId); if (type == EventLog::Type::ConferenceChatMessage) - d->cache(static_pointer_cast(eventLog)->getChatMessage(), storageId); + d->cache(static_pointer_cast(eventLog)->getChatMessage(), eventId); return true; } @@ -1759,13 +1626,12 @@ bool MainDb::addEvent (const shared_ptr &eventLog) { } bool MainDb::updateEvent (const shared_ptr &eventLog) { - const EventLogPrivate *dEventLog = eventLog->getPrivate(); - if (!dEventLog->dbKey.isValid()) { + if (!eventLog->getPrivate()->dbKey.isValid()) { lWarning() << "Unable to update an event that wasn't inserted yet!!!"; return false; } - return L_DB_EXCEPTION_HANDLER { + return L_DB_TRANSACTION { L_D(); switch (eventLog->getType()) { @@ -1809,7 +1675,7 @@ bool MainDb::deleteEvent (const shared_ptr &eventLog) { MainDb &mainDb = *core->getPrivate()->mainDb.get(); - return L_DB_EXCEPTION_HANDLER_C(&mainDb) { + return L_DB_TRANSACTION_C(&mainDb) { soci::session *session = mainDb.getPrivate()->dbSession.getBackendSession(); *session << "DELETE FROM event WHERE id = :id", soci::use(dEventKey->storageId); tr.commit(); @@ -1826,19 +1692,19 @@ bool MainDb::deleteEvent (const shared_ptr &eventLog) { } int MainDb::getEventCount (FilterMask mask) const { - string query = "SELECT COUNT(*) FROM event" + - buildSqlEventFilter({ ConferenceCallFilter, ConferenceChatMessageFilter, ConferenceInfoFilter, ConferenceInfoNoDeviceFilter }, mask); + const string query = "SELECT COUNT(*) FROM event" + + buildSqlEventFilter( + { ConferenceCallFilter, ConferenceChatMessageFilter, ConferenceInfoFilter, ConferenceInfoNoDeviceFilter }, + mask + ); - DurationLogger durationLogger( - "Get events count with mask=" + Utils::toString(mask) + "." - ); + DurationLogger durationLogger("Get event count with mask=" + Utils::toString(mask) + "."); - return L_DB_EXCEPTION_HANDLER { + return L_DB_TRANSACTION { L_D(); int count; - soci::session *session = d->dbSession.getBackendSession(); - *session << query, soci::into(count); + *d->dbSession.getBackendSession() << query, soci::into(count); return count; }; } @@ -1852,38 +1718,23 @@ shared_ptr MainDb::getEventFromKey (const MainDbKey &dbKey) { unique_ptr &q = dbKey.getPrivate()->core.lock()->getPrivate()->mainDb; MainDbPrivate *d = q->getPrivate(); - const long long &storageId = dbKey.getPrivate()->storageId; - { - shared_ptr event = d->getEventFromCache(storageId); - if (event) - return event; - } + const long long &eventId = dbKey.getPrivate()->storageId; + shared_ptr event = d->getEventFromCache(eventId); + if (event) + return event; - // TODO: Improve. Deal with all events in the future. - static const string query = "SELECT peer_sip_address.value, local_sip_address.value, type, event.creation_time" - " FROM event, conference_event, chat_room, sip_address AS peer_sip_address, sip_address as local_sip_address" - " WHERE event.id = :eventId" - " AND conference_event.event_id = event.id" - " AND conference_event.chat_room_id = chat_room.id" - " AND chat_room.peer_sip_address_id = peer_sip_address.id" - " AND chat_room.local_sip_address_id = local_sip_address.id"; + return L_DB_TRANSACTION_C(q.get()) { + // TODO: Improve. Deal with all events in the future. + soci::row row; + *d->dbSession.getBackendSession() << Statements::get(Statements::SelectConferenceEvent), + soci::into(row), soci::use(eventId); - return L_DB_EXCEPTION_HANDLER_C(q.get()) { - soci::session *session = d->dbSession.getBackendSession(); + ChatRoomId chatRoomId(IdentityAddress(row.get(14)), IdentityAddress(row.get(15))); + shared_ptr chatRoom = d->findChatRoom(chatRoomId); + if (!chatRoom) + return shared_ptr(); - string peerSipAddress; - string localSipAddress; - int type; - tm creationTime; - *session << query, soci::into(peerSipAddress), soci::into(localSipAddress), soci::into(type), - soci::into(creationTime), soci::use(storageId); - - return d->selectGenericConferenceEvent( - storageId, - EventLog::Type(type), - Utils::getTmAsTimeT(creationTime), - ChatRoomId(IdentityAddress(peerSipAddress), IdentityAddress(localSipAddress)) - ); + return d->selectGenericConferenceEvent(chatRoom, row); }; } @@ -1891,12 +1742,9 @@ list> MainDb::getConferenceNotifiedEvents ( const ChatRoomId &chatRoomId, unsigned int lastNotifyId ) const { - static const string query = "SELECT id, type, creation_time FROM event" - " WHERE id IN (" - " SELECT event_id FROM conference_notified_event WHERE event_id IN (" - " SELECT event_id FROM conference_event WHERE chat_room_id = :chatRoomId" - " ) AND notify_id > :lastNotifyId" - " )"; + // TODO: Optimize. + const string query = Statements::get(Statements::SelectConferenceEvents) + + string(" AND notify_id > :lastNotifyId"); DurationLogger durationLogger( "Get conference notified events of: (peer=" + chatRoomId.getPeerAddress().asString() + @@ -1904,7 +1752,7 @@ list> MainDb::getConferenceNotifiedEvents ( ", lastNotifyId=" + Utils::toString(lastNotifyId) + ")." ); - return L_DB_EXCEPTION_HANDLER { + return L_DB_TRANSACTION { L_D(); soci::session *session = d->dbSession.getBackendSession(); @@ -1913,18 +1761,8 @@ list> MainDb::getConferenceNotifiedEvents ( list> events; soci::rowset rows = (session->prepare << query, soci::use(dbChatRoomId), soci::use(lastNotifyId)); - for (const auto &row : rows) { - long long eventId = d->dbSession.resolveId(row, 0); - shared_ptr eventLog = d->getEventFromCache(eventId); - - events.push_back(eventLog ? eventLog : d->selectGenericConferenceEvent( - eventId, - EventLog::Type(row.get(1)), - Utils::getTmAsTimeT(row.get(2)), - chatRoomId - )); - } - + for (const auto &row : rows) + events.push_back(d->selectGenericConferenceNotifiedEvent(chatRoomId, row)); return events; }; } @@ -1935,7 +1773,7 @@ int MainDb::getChatMessageCount (const ChatRoomId &chatRoomId) const { ", local=" + chatRoomId.getLocalAddress().asString() + ")." ); - return L_DB_EXCEPTION_HANDLER { + return L_DB_TRANSACTION { L_D(); int count; @@ -1946,7 +1784,7 @@ int MainDb::getChatMessageCount (const ChatRoomId &chatRoomId) const { if (!chatRoomId.isValid()) *session << query, soci::into(count); else { - query += " WHERE event_id IN (" + query += " WHERE event_id IN (" " SELECT event_id FROM conference_event WHERE chat_room_id = :chatRoomId" ")"; @@ -1973,7 +1811,7 @@ int MainDb::getUnreadChatMessageCount (const ChatRoomId &chatRoomId) const { ", local=" + chatRoomId.getLocalAddress().asString() + ")." ); - return L_DB_EXCEPTION_HANDLER { + return L_DB_TRANSACTION { L_D(); int count = 0; @@ -1995,77 +1833,55 @@ void MainDb::markChatMessagesAsRead (const ChatRoomId &chatRoomId) const { if (getUnreadChatMessageCount(chatRoomId) == 0) return; - string query = "UPDATE conference_chat_message_event" - " SET state = " + Utils::toString(int(ChatMessage::State::Displayed)) + " "; - query += "WHERE"; - if (chatRoomId.isValid()) - query += " event_id IN (" - " SELECT event_id FROM conference_event WHERE chat_room_id = :chatRoomId" - ") AND"; - query += " direction = " + Utils::toString(int(ChatMessage::Direction::Incoming)); + static const string query = "UPDATE conference_chat_message_event" + " SET state = " + Utils::toString(int(ChatMessage::State::Displayed)) + + " WHERE event_id IN (" + " SELECT event_id FROM conference_event WHERE chat_room_id = :chatRoomId" + ") AND direction = " + Utils::toString(int(ChatMessage::Direction::Incoming)); DurationLogger durationLogger( "Mark chat messages as read of: (peer=" + chatRoomId.getPeerAddress().asString() + ", local=" + chatRoomId.getLocalAddress().asString() + ")." ); - L_DB_EXCEPTION_HANDLER { + L_DB_TRANSACTION { L_D(); - soci::session *session = d->dbSession.getBackendSession(); + const long long &dbChatRoomId = d->selectChatRoomId(chatRoomId); + *d->dbSession.getBackendSession() << query, soci::use(dbChatRoomId); - if (!chatRoomId.isValid()) - *session << query; - else { - const long long &dbChatRoomId = d->selectChatRoomId(chatRoomId); - *session << query, soci::use(dbChatRoomId); - } tr.commit(); }; } list> MainDb::getUnreadChatMessages (const ChatRoomId &chatRoomId) const { - string query = "SELECT id, creation_time FROM event WHERE" - " id IN (" - " SELECT conference_event.event_id FROM conference_event, conference_chat_message_event" - " WHERE"; - if (chatRoomId.isValid()) - query += " chat_room_id = :chatRoomId AND "; - query += " conference_event.event_id = conference_chat_message_event.event_id" - " AND direction = " + Utils::toString(int(ChatMessage::Direction::Incoming)) + - " AND state <> " + Utils::toString(int(ChatMessage::State::Displayed)) + - ")"; + // TODO: Optimize. + static const string query = Statements::get(Statements::SelectConferenceEvents) + + string(" AND direction = ") + Utils::toString(int(ChatMessage::Direction::Incoming)) + + " AND state <> " + Utils::toString(int(ChatMessage::State::Displayed)); DurationLogger durationLogger( "Get unread chat messages: (peer=" + chatRoomId.getPeerAddress().asString() + ", local=" + chatRoomId.getLocalAddress().asString() + ")." ); - return L_DB_EXCEPTION_HANDLER { + return L_DB_TRANSACTION { L_D(); soci::session *session = d->dbSession.getBackendSession(); - long long dbChatRoomId; - if (chatRoomId.isValid()) - dbChatRoomId = d->selectChatRoomId(chatRoomId); - + long long dbChatRoomId = d->selectChatRoomId(chatRoomId); + shared_ptr chatRoom = d->findChatRoom(chatRoomId); list> chatMessages; - soci::rowset rows = chatRoomId.isValid() - ? (session->prepare << query, soci::use(dbChatRoomId)) - : (session->prepare << query); + if (!chatRoom) + return chatMessages; + soci::rowset rows = (session->prepare << query, soci::use(dbChatRoomId)); for (const auto &row : rows) { - long long eventId = d->dbSession.resolveId(row, 0); - shared_ptr event = d->getEventFromCache(eventId); - - if (!event) - event = d->selectGenericConferenceEvent( - eventId, - EventLog::Type::ConferenceChatMessage, - Utils::getTmAsTimeT(row.get(1)), - chatRoomId - ); + shared_ptr event = d->selectGenericConferenceEvent( + chatRoom, + row + ); if (event) chatMessages.push_back(static_pointer_cast(event)->getChatMessage()); @@ -2076,24 +1892,23 @@ list> MainDb::getUnreadChatMessages (const ChatRoomId &c } list MainDb::getChatMessageParticipantStates (const shared_ptr &eventLog) const { - return L_DB_EXCEPTION_HANDLER { + return L_DB_TRANSACTION { L_D(); - soci::session *session = d->dbSession.getBackendSession(); - const EventLogPrivate *dEventLog = eventLog->getPrivate(); MainDbKeyPrivate *dEventKey = static_cast(dEventLog->dbKey).getPrivate(); const long long &eventId = dEventKey->storageId; - list states; - unsigned int state; - soci::statement statement = (session->prepare - << "SELECT state FROM chat_message_participant WHERE event_id = :eventId", - soci::into(state), soci::use(eventId) + unsigned int state; + soci::statement statement = ( + d->dbSession.getBackendSession()->prepare << "SELECT state FROM chat_message_participant WHERE event_id = :eventId", + soci::into(state), soci::use(eventId) ); statement.execute(); + + list states; while (statement.fetch()) - states.push_back(static_cast(state)); + states.push_back(ChatMessage::State(state)); return states; }; @@ -2103,22 +1918,20 @@ ChatMessage::State MainDb::getChatMessageParticipantState ( const shared_ptr &eventLog, const IdentityAddress &participantAddress ) const { - return L_DB_EXCEPTION_HANDLER { + return L_DB_TRANSACTION { L_D(); - soci::session *session = d->dbSession.getBackendSession(); - const EventLogPrivate *dEventLog = eventLog->getPrivate(); MainDbKeyPrivate *dEventKey = static_cast(dEventLog->dbKey).getPrivate(); const long long &eventId = dEventKey->storageId; const long long &participantSipAddressId = d->selectSipAddressId(participantAddress.asString()); - unsigned int state; - *session << "SELECT state FROM chat_message_participant" + unsigned int state; + *d->dbSession.getBackendSession() << "SELECT state FROM chat_message_participant" " WHERE event_id = :eventId AND participant_sip_address_id = :participantSipAddressId", soci::into(state), soci::use(eventId), soci::use(participantSipAddressId); - return static_cast(state); + return ChatMessage::State(state); }; } @@ -2127,18 +1940,16 @@ void MainDb::setChatMessageParticipantState ( const IdentityAddress &participantAddress, ChatMessage::State state ) { - L_DB_EXCEPTION_HANDLER { + L_DB_TRANSACTION { L_D(); - soci::session *session = d->dbSession.getBackendSession(); - const EventLogPrivate *dEventLog = eventLog->getPrivate(); MainDbKeyPrivate *dEventKey = static_cast(dEventLog->dbKey).getPrivate(); const long long &eventId = dEventKey->storageId; const long long &participantSipAddressId = d->selectSipAddressId(participantAddress.asString()); int stateInt = static_cast(state); - *session << "UPDATE chat_message_participant SET state = :state" + *d->dbSession.getBackendSession() << "UPDATE chat_message_participant SET state = :state" " WHERE event_id = :eventId AND participant_sip_address_id = :participantSipAddressId", soci::use(stateInt), soci::use(eventId), soci::use(participantSipAddressId); @@ -2158,44 +1969,33 @@ list> MainDb::findChatMessages ( const ChatRoomId &chatRoomId, const string &imdnMessageId ) const { - static const string query = "SELECT id, type, creation_time FROM event" - " WHERE id IN (" - " SELECT event_id FROM conference_event" - " WHERE event_id IN (SELECT event_id FROM conference_chat_message_event WHERE imdn_message_id = :imdnMessageId)" - " AND chat_room_id = :chatRoomId" - " )"; + // TODO: Optimize. + static const string query = Statements::get(Statements::SelectConferenceEvents) + + string(" AND imdn_message_id = :imdnMessageId"); DurationLogger durationLogger( "Find chat messages: (peer=" + chatRoomId.getPeerAddress().asString() + ", local=" + chatRoomId.getLocalAddress().asString() + ")." ); - return L_DB_EXCEPTION_HANDLER { + return L_DB_TRANSACTION { L_D(); - soci::session *session = d->dbSession.getBackendSession(); - + shared_ptr chatRoom = d->findChatRoom(chatRoomId); list> chatMessages; + if (!chatRoom) + return chatMessages; const long long &dbChatRoomId = d->selectChatRoomId(chatRoomId); - soci::rowset rows = (session->prepare << query, soci::use(imdnMessageId), soci::use(dbChatRoomId)); + soci::rowset rows = ( + d->dbSession.getBackendSession()->prepare << query, soci::use(dbChatRoomId), soci::use(imdnMessageId) + ); for (const auto &row : rows) { - long long eventId = d->dbSession.resolveId(row, 0); - shared_ptr event = d->getEventFromCache(eventId); - - if (!event) - event = d->selectGenericConferenceEvent( - eventId, - EventLog::Type(row.get(1)), - Utils::getTmAsTimeT(row.get(2)), - chatRoomId - ); - + shared_ptr event = d->selectGenericConferenceEvent(chatRoom, row); if (event) { L_ASSERT(event->getType() == EventLog::Type::ConferenceChatMessage); chatMessages.push_back(static_pointer_cast(event)->getChatMessage()); - } else - lWarning() << "Unable to fetch event: " << eventId; + } } return chatMessages; @@ -2223,18 +2023,18 @@ list> MainDb::getHistoryRange ( return events; } - string query = Statements::get(Statements::SelectConferenceEvents, Backend::Sqlite3) + buildSqlEventFilter({ + string query = Statements::get(Statements::SelectConferenceEvents) + buildSqlEventFilter({ ConferenceCallFilter, ConferenceChatMessageFilter, ConferenceInfoFilter, ConferenceInfoNoDeviceFilter }, mask, "AND"); - query += " ORDER BY event_id DESC"; + query += " ORDER BY event_id DESC"; if (end > 0) - query += " LIMIT " + Utils::toString(end - begin); + query += " LIMIT " + Utils::toString(end - begin); else - query += " LIMIT " + d->dbSession.noLimitValue(); + query += " LIMIT " + d->dbSession.noLimitValue(); if (begin > 0) - query += " OFFSET " + Utils::toString(begin); + query += " OFFSET " + Utils::toString(begin); DurationLogger durationLogger( "Get history range of: (peer=" + chatRoomId.getPeerAddress().asString() + @@ -2242,57 +2042,19 @@ list> MainDb::getHistoryRange ( ", begin=" + Utils::toString(begin) + ", end=" + Utils::toString(end) + ")." ); - return L_DB_EXCEPTION_HANDLER { + return L_DB_TRANSACTION { L_D(); - soci::session *session = d->dbSession.getBackendSession(); - - shared_ptr core = getCore(); - shared_ptr chatRoom = core->findChatRoom(chatRoomId); - if (!chatRoom) { - lError() << "Unable to find chat room storage id of (peer=" + - chatRoomId.getPeerAddress().asString() + - ", local=" + chatRoomId.getLocalAddress().asString() + "`)."; + shared_ptr chatRoom = d->findChatRoom(chatRoomId); + if (!chatRoom) return events; - } const long long &dbChatRoomId = d->selectChatRoomId(chatRoomId); - soci::rowset rows = (session->prepare << query, soci::use(dbChatRoomId)); + soci::rowset rows = (d->dbSession.getBackendSession()->prepare << query, soci::use(dbChatRoomId)); for (const auto &row : rows) { - long long eventId = d->dbSession.resolveId(row, 0); - shared_ptr event = d->getEventFromCache(eventId); - - if (!event) { - EventLog::Type type = EventLog::Type(row.get(1)); - - // TODO: Remove me. Performance workaround. - if (type == EventLog::Type::ConferenceChatMessage) - event = d->selectConferenceChatMessageEvent( - eventId, - type, - Utils::getTmAsTimeT(row.get(2)), - chatRoom, - row.get(3), - row.get(4), - row.get(5), - row.get(6), - row.get(7), - row.get(8), - row.get(9) - ); - else - event = d->selectGenericConferenceEvent( - eventId, - type, - Utils::getTmAsTimeT(row.get(2)), - chatRoomId - ); - } - + shared_ptr event = d->selectGenericConferenceEvent(chatRoom, row); if (event) events.push_front(event); - else - lWarning() << "Unable to fetch event: " << eventId; } return events; @@ -2306,21 +2068,31 @@ int MainDb::getHistorySize (const ChatRoomId &chatRoomId, FilterMask mask) const ConferenceCallFilter, ConferenceChatMessageFilter, ConferenceInfoFilter, ConferenceInfoNoDeviceFilter }, mask, "AND"); - return L_DB_EXCEPTION_HANDLER { + return L_DB_TRANSACTION { L_D(); - soci::session *session = d->dbSession.getBackendSession(); - int count; const long long &dbChatRoomId = d->selectChatRoomId(chatRoomId); - *session << query, soci::into(count), soci::use(dbChatRoomId); + *d->dbSession.getBackendSession() << query, soci::into(count), soci::use(dbChatRoomId); return count; }; } +template +static void fetchContentAppData (soci::session *session, Content &content, long long contentId, T &data) { + static const string query = "SELECT name, data FROM chat_message_content_app_data" + " WHERE chat_message_content_id = :contentId"; + + string name; + soci::statement statement = (session->prepare << query, soci::use(contentId), soci::into(name), soci::into(data)); + statement.execute(); + while (statement.fetch()) + content.setAppData(name, blobToString(data)); +} + void MainDb::loadChatMessageContents (const shared_ptr &chatMessage) { - L_DB_EXCEPTION_HANDLER { + L_DB_TRANSACTION { L_D(); soci::session *session = d->dbSession.getBackendSession(); @@ -2395,15 +2167,13 @@ void MainDb::cleanHistory (const ChatRoomId &chatRoomId, FilterMask mask) { ", mask=" + Utils::toString(mask) + ")." ); - L_DB_EXCEPTION_HANDLER { + L_DB_TRANSACTION { L_D(); - soci::session *session = d->dbSession.getBackendSession(); - const long long &dbChatRoomId = d->selectChatRoomId(chatRoomId); d->invalidConferenceEventsFromQuery(query, dbChatRoomId); - *session << "DELETE FROM event WHERE id IN (" + query + ")", soci::use(dbChatRoomId); + *d->dbSession.getBackendSession() << "DELETE FROM event WHERE id IN (" + query + ")", soci::use(dbChatRoomId); tr.commit(); }; @@ -2412,15 +2182,15 @@ void MainDb::cleanHistory (const ChatRoomId &chatRoomId, FilterMask mask) { // ----------------------------------------------------------------------------- list> MainDb::getChatRooms () const { - static const string query = "SELECT chat_room.id, peer_sip_address.value, local_sip_address.value, " - "creation_time, last_update_time, capabilities, subject, last_notify_id, flags" - " FROM chat_room, sip_address AS peer_sip_address, sip_address AS local_sip_address" - " WHERE chat_room.peer_sip_address_id = peer_sip_address.id AND chat_room.local_sip_address_id = local_sip_address.id" - " ORDER BY last_update_time DESC"; + static const string query = "SELECT chat_room.id, peer_sip_address.value, local_sip_address.value," + " creation_time, last_update_time, capabilities, subject, last_notify_id, flags" + " FROM chat_room, sip_address AS peer_sip_address, sip_address AS local_sip_address" + " WHERE chat_room.peer_sip_address_id = peer_sip_address.id AND chat_room.local_sip_address_id = local_sip_address.id" + " ORDER BY last_update_time DESC"; DurationLogger durationLogger("Get chat rooms."); - return L_DB_EXCEPTION_HANDLER { + return L_DB_TRANSACTION { L_D(); list> chatRooms; @@ -2456,10 +2226,10 @@ list> MainDb::getChatRooms () const { const long long &dbChatRoomId = d->dbSession.resolveId(row, 0); static const string query = "SELECT chat_room_participant.id, sip_address.value, is_admin" - " FROM sip_address, chat_room, chat_room_participant" - " WHERE chat_room.id = :chatRoomId" - " AND sip_address.id = chat_room_participant.participant_sip_address_id" - " AND chat_room_participant.chat_room_id = chat_room.id"; + " FROM sip_address, chat_room, chat_room_participant" + " WHERE chat_room.id = :chatRoomId" + " AND sip_address.id = chat_room_participant.participant_sip_address_id" + " AND chat_room_participant.chat_room_id = chat_room.id"; // Fetch participants. soci::rowset rows = (session->prepare << query, soci::use(dbChatRoomId)); @@ -2473,8 +2243,8 @@ list> MainDb::getChatRooms () const { { const long long &participantId = d->dbSession.resolveId(row, 0); static const string query = "SELECT sip_address.value, state FROM chat_room_participant_device, sip_address" - " WHERE chat_room_participant_id = :participantId" - " AND participant_device_sip_address_id = sip_address.id"; + " WHERE chat_room_participant_id = :participantId" + " AND participant_device_sip_address_id = sip_address.id"; soci::rowset rows = (session->prepare << query, soci::use(participantId)); for (const auto &row : rows) { @@ -2546,13 +2316,7 @@ list> MainDb::getChatRooms () const { } void MainDb::insertChatRoom (const shared_ptr &chatRoom) { - const ChatRoomId &chatRoomId = chatRoom->getChatRoomId(); - DurationLogger durationLogger( - "Insert chat room: (peer=" + chatRoomId.getPeerAddress().asString() + - ", local=" + chatRoomId.getLocalAddress().asString() + ")." - ); - - L_DB_EXCEPTION_HANDLER { + L_DB_TRANSACTION { L_D(); d->insertChatRoom(chatRoom); @@ -2561,14 +2325,8 @@ void MainDb::insertChatRoom (const shared_ptr &chatRoom) { } void MainDb::deleteChatRoom (const ChatRoomId &chatRoomId) { - DurationLogger durationLogger( - "Delete chat room: (peer=" + chatRoomId.getPeerAddress().asString() + - ", local=" + chatRoomId.getLocalAddress().asString() + "`)." - ); - - L_DB_EXCEPTION_HANDLER { + L_DB_TRANSACTION { L_D(); - soci::session *session = d->dbSession.getBackendSession(); const long long &dbChatRoomId = d->selectChatRoomId(chatRoomId); @@ -2577,7 +2335,7 @@ void MainDb::deleteChatRoom (const ChatRoomId &chatRoomId) { dbChatRoomId ); - *session << "DELETE FROM chat_room WHERE id = :chatRoomId", soci::use(dbChatRoomId); + *d->dbSession.getBackendSession() << "DELETE FROM chat_room WHERE id = :chatRoomId", soci::use(dbChatRoomId); tr.commit(); }; @@ -2590,13 +2348,10 @@ void MainDb::migrateBasicToClientGroupChatRoom ( L_ASSERT(basicChatRoom->getCapabilities().isSet(ChatRoom::Capabilities::Basic)); L_ASSERT(clientGroupChatRoom->getCapabilities().isSet(ChatRoom::Capabilities::Conference)); - L_DB_EXCEPTION_HANDLER { + L_DB_TRANSACTION { L_D(); // TODO: Update events and chat messages. (Or wait signals.) - - soci::session *session = d->dbSession.getBackendSession(); - const long long &dbChatRoomId = d->selectChatRoomId(basicChatRoom->getChatRoomId()); const ChatRoomId &newChatRoomId = clientGroupChatRoom->getChatRoomId(); @@ -2604,11 +2359,11 @@ void MainDb::migrateBasicToClientGroupChatRoom ( const long long &localSipAddressId = d->insertSipAddress(newChatRoomId.getLocalAddress().asString()); const int &capabilities = clientGroupChatRoom->getCapabilities(); - *session << "UPDATE chat_room" - " SET capabilities = :capabilities," - " peer_sip_address_id = :peerSipAddressId," - " local_sip_address_id = :localSipAddressId" - " WHERE id = :chatRoomId", soci::use(capabilities), soci::use(peerSipAddressId), + *d->dbSession.getBackendSession() << "UPDATE chat_room" + " SET capabilities = :capabilities," + " peer_sip_address_id = :peerSipAddressId," + " local_sip_address_id = :localSipAddressId" + " WHERE id = :chatRoomId", soci::use(capabilities), soci::use(peerSipAddressId), soci::use(localSipAddressId), soci::use(dbChatRoomId); shared_ptr me = clientGroupChatRoom->getMe(); @@ -2642,11 +2397,9 @@ IdentityAddress MainDb::findMissingOneToOneConferenceChatRoomParticipantAddress L_ASSERT(chatRoom->getCapabilities() & ChatRoom::Capabilities::OneToOne); L_ASSERT(chatRoom->getParticipantCount() == 1); - return L_DB_EXCEPTION_HANDLER { + return L_DB_TRANSACTION { L_D(); - soci::session *session = d->dbSession.getBackendSession(); - string missingParticipantAddress; string participantASipAddress; string participantBSipAddress; @@ -2654,7 +2407,7 @@ IdentityAddress MainDb::findMissingOneToOneConferenceChatRoomParticipantAddress const long long &chatRoomId = d->selectChatRoomId(chatRoom->getChatRoomId()); L_ASSERT(chatRoomId != -1); - *session << "SELECT participant_a_sip_address.value, participant_b_sip_address.value" + *d->dbSession.getBackendSession() << "SELECT participant_a_sip_address.value, participant_b_sip_address.value" " FROM one_to_one_chat_room, sip_address AS participant_a_sip_address, sip_address AS participant_b_sip_address" " WHERE chat_room_id = :chatRoomId" " AND participant_a_sip_address_id = participant_a_sip_address.id" @@ -2675,20 +2428,18 @@ IdentityAddress MainDb::findOneToOneConferenceChatRoomAddress ( const IdentityAddress &participantA, const IdentityAddress &participantB ) const { - return L_DB_EXCEPTION_HANDLER { + return L_DB_TRANSACTION { L_D(); - soci::session *session = d->dbSession.getBackendSession(); - const long long &participantASipAddressId = d->selectSipAddressId(participantA.asString()); const long long &participantBSipAddressId = d->selectSipAddressId(participantB.asString()); - if ((participantASipAddressId == -1) || (participantBSipAddressId == -1)) + if (participantASipAddressId == -1 || participantBSipAddressId == -1) return IdentityAddress(); const long long &chatRoomId = d->selectOneToOneChatRoomId(participantASipAddressId, participantBSipAddressId); string chatRoomAddress; - *session << "SELECT sip_address.value" + *d->dbSession.getBackendSession() << "SELECT sip_address.value" " FROM chat_room, sip_address" " WHERE chat_room.id = :chatRoomId AND peer_sip_address_id = sip_address.id", soci::use(chatRoomId), soci::into(chatRoomAddress); @@ -2701,7 +2452,7 @@ void MainDb::insertOneToOneConferenceChatRoom (const shared_ptrgetCore()->getCCore())); L_ASSERT(chatRoom->getCapabilities() & ChatRoom::Capabilities::OneToOne); - L_DB_EXCEPTION_HANDLER { + L_DB_TRANSACTION { L_D(); const list> &participants = chatRoom->getParticipants(); @@ -2722,7 +2473,7 @@ void MainDb::insertOneToOneConferenceChatRoom (const shared_ptrdbSession.getBackendSession(); @@ -2747,18 +2498,16 @@ void MainDb::updateChatRoomParticipantDevice ( const shared_ptr &chatRoom, const shared_ptr &device ) { - L_DB_EXCEPTION_HANDLER { + L_DB_TRANSACTION { L_D(); - soci::session *session = d->dbSession.getBackendSession(); - const long long &dbChatRoomId = d->selectChatRoomId(chatRoom->getChatRoomId()); const long long &participantSipAddressId = d->selectSipAddressId(device->getParticipant()->getAddress().asString()); const long long &participantId = d->selectChatRoomParticipantId(dbChatRoomId, participantSipAddressId); const long long &participantSipDeviceAddressId = d->selectSipAddressId(device->getAddress().asString()); unsigned int state = static_cast(device->getState()); - *session << "UPDATE chat_room_participant_device SET state = :state" - " WHERE chat_room_participant_id = :participantId AND participant_device_sip_address_id = :participantSipDeviceAddressId", + *d->dbSession.getBackendSession() << "UPDATE chat_room_participant_device SET state = :state" + " WHERE chat_room_participant_id = :participantId AND participant_device_sip_address_id = :participantSipDeviceAddressId", soci::use(state), soci::use(participantId), soci::use(participantSipDeviceAddressId); tr.commit(); @@ -2788,103 +2537,4 @@ bool MainDb::import (Backend, const string ¶meters) { return true; } -// ----------------------------------------------------------------------------- -// No backend. -// ----------------------------------------------------------------------------- - -#else - -void MainDb::init () {} - -bool MainDb::addEvent (const shared_ptr &) { - return false; -} - -bool MainDb::updateEvent (const shared_ptr &) { - return false; -} - -bool MainDb::deleteEvent (const shared_ptr &) { - return false; -} - -int MainDb::getEventCount (FilterMask) const { - return 0; -} - -shared_ptr MainDb::getEventFromKey (const MainDbKey &) { - return nullptr; -} - -list> MainDb::getConferenceNotifiedEvents ( - const ChatRoomId &, - unsigned int -) const { - return list>(); -} - -int MainDb::getChatMessageCount (const ChatRoomId &) const { - return 0; -} - -int MainDb::getUnreadChatMessageCount (const ChatRoomId &) const { - return 0; -} - -shared_ptr MainDb::getLastChatMessage (const ChatRoomId &) const { - return nullptr; -} - -list> MainDb::findChatMessages (const ChatRoomId &, const string &) const { - return list>(); -} - -void MainDb::markChatMessagesAsRead (const ChatRoomId &) const {} - -list> MainDb::getUnreadChatMessages (const ChatRoomId &) const { - return list>(); -} - -list> MainDb::getHistory (const ChatRoomId &, int, FilterMask) const { - return list>(); -} - -list> MainDb::getHistoryRange (const ChatRoomId &, int, int, FilterMask) const { - return list>(); -} - -int MainDb::getHistorySize (const ChatRoomId &, FilterMask) const { - return 0; -} - -list> MainDb::getChatRooms () const { - return list>(); -} - -void MainDb::insertChatRoom (const shared_ptr &) {} - -void MainDb::deleteChatRoom (const ChatRoomId &) {} - -void MainDb::migrateBasicToClientGroupChatRoom ( - const shared_ptr &, - const shared_ptr & -) {} - -IdentityAddress MainDb::findOneToOneConferenceChatRoomAddress ( - const IdentityAddress &, - const IdentityAddress & -) const { - return IdentityAddress(); -} - -void MainDb::loadChatMessageContents (const shared_ptr &) {} - -void MainDb::cleanHistory (const ChatRoomId &, FilterMask) {} - -bool MainDb::import (Backend, const string &) { - return false; -} - -#endif // ifdef SOCI_ENABLED - LINPHONE_END_NAMESPACE diff --git a/src/db/main-db.h b/src/db/main-db.h index 14e7294c9..f0f4b6f06 100644 --- a/src/db/main-db.h +++ b/src/db/main-db.h @@ -43,7 +43,7 @@ class ParticipantDevice; class MainDb : public AbstractDb, public CoreAccessor { template - friend class DbExceptionHandler; + friend class DbTransaction; friend class MainDbChatMessageKey; friend class MainDbEventKey; @@ -87,8 +87,8 @@ public: int getChatMessageCount (const ChatRoomId &chatRoomId = ChatRoomId()) const; int getUnreadChatMessageCount (const ChatRoomId &chatRoomId = ChatRoomId()) const; - void markChatMessagesAsRead (const ChatRoomId &chatRoomId = ChatRoomId()) const; - std::list> getUnreadChatMessages (const ChatRoomId &chatRoomId = ChatRoomId()) const; + void markChatMessagesAsRead (const ChatRoomId &chatRoomId) const; + std::list> getUnreadChatMessages (const ChatRoomId &chatRoomId) const; std::list getChatMessageParticipantStates (const std::shared_ptr &eventLog) const; ChatMessage::State getChatMessageParticipantState ( diff --git a/src/db/session/db-session.cpp b/src/db/session/db-session.cpp index b38550e35..e9fbc4450 100644 --- a/src/db/session/db-session.cpp +++ b/src/db/session/db-session.cpp @@ -36,25 +36,19 @@ public: Sqlite3 } backend = Backend::None; - #ifdef SOCI_ENABLED - std::unique_ptr backendSession; - #endif // ifdef SOCI_ENABLED + std::unique_ptr backendSession; }; DbSession::DbSession () : mPrivate(new DbSessionPrivate) {} DbSession::DbSession (const string &uri) : DbSession() { - #ifdef SOCI_ENABLED - try { - L_D(); - d->backendSession = makeUnique(uri); - d->backend = !uri.find("mysql") ? DbSessionPrivate::Backend::Mysql : DbSessionPrivate::Backend::Sqlite3; - } catch (const exception &e) { - lWarning() << "Unable to build db session with uri: " << e.what(); - } - #else - lWarning() << "Unable to build db session with uri: soci not enabled."; - #endif // ifdef SOCI_ENABLED + try { + L_D(); + d->backendSession = makeUnique(uri); + d->backend = !uri.find("mysql") ? DbSessionPrivate::Backend::Mysql : DbSessionPrivate::Backend::Sqlite3; + } catch (const exception &e) { + lWarning() << "Unable to build db session with uri: " << e.what(); + } } DbSession::DbSession (DbSession &&other) : mPrivate(other.mPrivate) { @@ -76,12 +70,8 @@ DbSession::operator bool () const { } soci::session *DbSession::getBackendSession () const { - #ifdef SOCI_ENABLED - L_D(); - return d->backendSession.get(); - #else - return nullptr; - #endif // ifdef SOCI_ENABLED + L_D(); + return d->backendSession.get(); } string DbSession::primaryKeyStr (const string &type) const { @@ -183,68 +173,58 @@ long long DbSession::getLastInsertId () const { break; } - #ifdef SOCI_ENABLED - *d->backendSession << sql, soci::into(id); - #endif // ifdef SOCI_ENABLED + *d->backendSession << sql, soci::into(id); return id; } void DbSession::enableForeignKeys (bool status) { - #ifdef SOCI_ENABLED - L_D(); - switch (d->backend) { - case DbSessionPrivate::Backend::Mysql: - *d->backendSession << string("SET FOREIGN_KEY_CHECKS = ") + (status ? "1" : "0"); - break; - case DbSessionPrivate::Backend::Sqlite3: - *d->backendSession << string("PRAGMA foreign_keys = ") + (status ? "ON" : "OFF"); - break; - case DbSessionPrivate::Backend::None: - break; - } - #endif // ifdef SOCI_ENABLED + L_D(); + + switch (d->backend) { + case DbSessionPrivate::Backend::Mysql: + *d->backendSession << string("SET FOREIGN_KEY_CHECKS = ") + (status ? "1" : "0"); + break; + case DbSessionPrivate::Backend::Sqlite3: + *d->backendSession << string("PRAGMA foreign_keys = ") + (status ? "ON" : "OFF"); + break; + case DbSessionPrivate::Backend::None: + break; + } } bool DbSession::checkTableExists (const string &table) const { - #ifdef SOCI_ENABLED - L_D(); - soci::session *session = d->backendSession.get(); - switch (d->backend) { - case DbSessionPrivate::Backend::Mysql: - *session << "SHOW TABLES LIKE :table", soci::use(table); - return session->got_data() > 0; - case DbSessionPrivate::Backend::Sqlite3: - *session << "SELECT name FROM sqlite_master WHERE type='table' AND name=:table", soci::use(table); - return session->got_data() > 0; - case DbSessionPrivate::Backend::None: - return false; - } - L_ASSERT(false); - #else - (void)table; - #endif // ifdef SOCI_ENABLED + L_D(); + soci::session *session = d->backendSession.get(); + switch (d->backend) { + case DbSessionPrivate::Backend::Mysql: + *session << "SHOW TABLES LIKE :table", soci::use(table); + return session->got_data() > 0; + case DbSessionPrivate::Backend::Sqlite3: + *session << "SELECT name FROM sqlite_master WHERE type='table' AND name=:table", soci::use(table); + return session->got_data() > 0; + case DbSessionPrivate::Backend::None: + return false; + } + + L_ASSERT(false); return false; } long long DbSession::resolveId (const soci::row &row, int col) const { - #ifdef SOCI_ENABLED - L_D(); - switch (d->backend) { - case DbSessionPrivate::Backend::Mysql: - return static_cast(row.get(0)); - case DbSessionPrivate::Backend::Sqlite3: - return static_cast(row.get(0)); - case DbSessionPrivate::Backend::None: - return 0; - } - L_ASSERT(false); - #else - (void)row; - (void)col; - #endif // ifdef SOCI_ENABLED + L_D(); + switch (d->backend) { + case DbSessionPrivate::Backend::Mysql: + return static_cast(row.get(0)); + case DbSessionPrivate::Backend::Sqlite3: + return static_cast(row.get(0)); + case DbSessionPrivate::Backend::None: + return 0; + } + + L_ASSERT(false); return 0; } diff --git a/src/db/session/db-session.h b/src/db/session/db-session.h index 6d4bf7b1c..0189bf997 100644 --- a/src/db/session/db-session.h +++ b/src/db/session/db-session.h @@ -20,28 +20,17 @@ #ifndef _L_DB_SESSION_H_ #define _L_DB_SESSION_H_ -#ifdef SOCI_ENABLED - #include -#endif // ifdef SOCI_ENABLED +#include -#include "object/clonable-object.h" +#include "linphone/utils/general.h" // ============================================================================= -#ifndef SOCI_ENABLED - namespace soci { - class row; - class session; - } -#endif // ifndef SOCI_ENABLED - LINPHONE_BEGIN_NAMESPACE class DbSessionPrivate; class DbSession { - friend class DbSessionProvider; - public: DbSession (); explicit DbSession (const std::string &uri);