Commit 76342c71 authored by Ronan's avatar Ronan

feat(MainDb): reworking, better code (performance and fixes)

parent 556fb1a6
......@@ -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}")
......
......@@ -20,6 +20,8 @@
#ifndef _L_ADDRESS_H_
#define _L_ADDRESS_H_
#include <ostream>
#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_
......@@ -20,6 +20,8 @@
#ifndef _L_IDENTITY_ADDRESS_H_
#define _L_IDENTITY_ADDRESS_H_
#include <ostream>
#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_
......@@ -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.
......
......@@ -162,10 +162,8 @@ shared_ptr<AbstractChatRoom> 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<ChatRoom>();
lInfo() << "Unable to find chat room in RAM: " << chatRoomId << ".";
return nullptr;
}
list<shared_ptr<AbstractChatRoom>> Core::findChatRooms (const IdentityAddress &peerAddress) const {
......
......@@ -30,8 +30,6 @@ LINPHONE_BEGIN_NAMESPACE
class AbstractDbPrivate : public ObjectPrivate {
public:
AbstractDbPrivate () = default;
DbSession dbSession;
private:
......
......@@ -21,9 +21,9 @@
#include <TargetConditionals.h>
#endif // ifdef __APPLE__
#if defined(SOCI_ENABLED) && (TARGET_OS_IPHONE || defined(__ANDROID__))
#if (TARGET_OS_IPHONE || defined(__ANDROID__))
#include <sqlite3.h>
#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 &parameters) {
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 &parameters) {
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...";
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;
}
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;
}
} 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;
}
......
......@@ -28,7 +28,7 @@ LINPHONE_BEGIN_NAMESPACE
class AbstractDbPrivate;
class LINPHONE_PUBLIC AbstractDb : public Object {
class AbstractDb : public Object {
public:
enum Backend {
Mysql,
......
/*
* 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 <soci/soci.h>
#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 *>(_mainDb);
return *this;
......@@ -80,7 +78,7 @@ struct DbExceptionHandlerInfo {
};
template<typename Function>
class DbExceptionHandler {
class DbTransaction {
using InternalReturnType = typename std::remove_reference<
decltype(std::declval<Function>()(std::declval<SmartTransaction &>()))
>::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 Function>
typename DbExceptionHandler<Function>::ReturnType operator* (DbExceptionHandlerInfo &info, Function &&function) {
return DbExceptionHandler<Function>(info, std::forward<Function>(function));
typename DbTransaction<Function>::ReturnType operator* (DbTransactionInfo &info, Function &&function) {
return DbTransaction<Function>(info, std::forward<Function>(function));
}
LINPHONE_END_NAMESPACE
#endif // ifndef _L_DB_EXCEPTION_HANDLER_H_
#endif // ifndef _L_DB_TRANSACTION_H_
......@@ -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) {
......
......@@ -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);
}
......
......@@ -22,6 +22,8 @@
#include <unordered_map>
#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<long long, std::weak_ptr<ChatMessage>> storageIdToChatMessage;
private:
// ---------------------------------------------------------------------------
// Misc helpers.
// ---------------------------------------------------------------------------
std::shared_ptr<AbstractChatRoom> 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<AbstractChatRoom> &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<tm>(2));
}
unsigned int getConferenceEventNotifyIdFromRow (const soci::row &row) const {
L_Q();
return q->getBackend() == MainDb::Backend::Mysql
? row.get<unsigned int>(10, 0)
: static_cast<unsigned int>(row.get<int>(10, 0));
}
std::shared_ptr<EventLog> selectGenericConferenceEvent (
long long eventId,
EventLog::Type type,
time_t creationTime,
const ChatRoomId &chatRoomId
const std::shared_ptr<AbstractChatRoom> &chatRoom,
const soci::row &row
) const;
std::shared_ptr<EventLog> selectConferenceEvent (
long long eventId,
EventLog::Type type,
time_t creationTime,
const ChatRoomId &chatRoomId
std::shared_ptr<EventLog> selectGenericConferenceNotifiedEvent (
const ChatRoomId &chatRoomId,
const soci::row &row
) const;
std::shared_ptr<EventLog> selectConferenceCallEvent (
long long eventId,
std::shared_ptr<EventLog> selectConferenceEvent (
const ChatRoomId &chatRoomId,
EventLog::Type type,
time_t creationTime,
const ChatRoomId &chatRoomId
const soci::row &row
) const;
std::shared_ptr<EventLog> selectConferenceChatMessageEvent (
long long eventId,
std::shared_ptr<EventLog> selectConferenceCallEvent (
const ChatRoomId &chatRoomId,
EventLog::Type type,
time_t creationTime,
const ChatRoomId &chatRoomId
const soci::row &row
) const;
// TODO: Remove me. Workaround to increase fetch performance.
std::shared_ptr<EventLog> selectConferenceChatMessageEvent (
long long eventId,
const std::shared_ptr<AbstractChatRoom> &chatRoom,
EventLog::Type type,
time_t creationTime,
std::shared_ptr<AbstractChatRoom> &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<EventLog> selectConferenceParticipantEvent (
long long eventId,
const ChatRoomId &chatRoomId,
EventLog::Type type,
time_t creationTime,
const ChatRoomId &chatRoomId
const soci::row &row
) const;
std::shared_ptr<EventLog> selectConferenceParticipantDeviceEvent (
long long eventId,
const ChatRoomId &chatRoomId,
EventLog::Type type,
time_t creationTime,
const ChatRoomId &chatRoomId
const soci::row &row
) const;
std::shared_ptr<EventLog> 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> &eventLog);
......
......@@ -20,7 +20,6 @@
#include <ctime>
#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> &core) : AbstractDb(*new MainDbPrivate), CoreAccessor(core) {}
static inline vector<char> blobToVector (soci::blob &in) {
size_t len = in.get_len();
if (!len)
return vector<char>();
vector<char> out(len);
in.read(0, &out[0], len);
return out;
}
static inline string blobToString (soci::blob &in) {
vector<char> out = blobToVector(in);
return string(out.begin(), out.end());
}
static constexpr string &blobToString (string &in) {
return in;
}
template<typename T>
static T getValueFromRow (const soci::row &row, int index, bool &isNull) {
isNull = false;
#ifdef SOCI_ENABLED
if (row.get_indicator(size_t(index)) == soci::i_null) {
isNull = true;
return T();
}
return row.get<T>(size_t(index));
}
// -----------------------------------------------------------------------------
// Event filter tools.
......@@ -202,45 +222,39 @@ static string buildSqlEventFilter (
return sql;
}
// -----------------------------------------------------------------------------
// Misc helpers.
// -----------------------------------------------------------------------------
static inline vector<char> blobToVector (soci::blob &in) {
size_t len = in.get_len();
if (!len)
return vector<char>();
vector<char> out(len);
in.read(0, &out[0], len);
return out;
}
static inline string blobToString (soci::blob &in) {
vector<char> out = blobToVector(in);
return string(out.begin(), out.end());
shared_ptr<AbstractChatRoom> MainDbPrivate::findChatRoom (const ChatRoomId &chatRoomId) const {
L_Q();
shared_ptr<AbstractChatRoom> chatRoom = q->getCore()->findChatRoom(chatRoomId);
if (!chatRoom)
lError() << "Unable to find chat room: " << chatRoomId << ".";
return chatRoom;
}
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<AbstractChatRoom> &chatRoom) {
soci::session *session = dbSession.getBackendSession();