Skip to content
GitLab
Projects
Groups
Snippets
Help
Loading...
Help
What's new
10
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
Open sidebar
BC
public
liblinphone
Commits
0c7956d5
Commit
0c7956d5
authored
Feb 21, 2018
by
Ghislain MARY
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Revert "Revert "feat(MainDb): increase performance of get history range""
This reverts commit
fe9a9a26
.
parent
2dce689f
Changes
9
Hide whitespace changes
Inline
Side-by-side
Showing
9 changed files
with
492 additions
and
195 deletions
+492
-195
src/CMakeLists.txt
src/CMakeLists.txt
+9
-3
src/chat/chat-message/chat-message-p.h
src/chat/chat-message/chat-message-p.h
+10
-3
src/chat/chat-message/chat-message.cpp
src/chat/chat-message/chat-message.cpp
+28
-4
src/db/internal/safe-transaction.h
src/db/internal/safe-transaction.h
+141
-0
src/db/internal/statements.cpp
src/db/internal/statements.cpp
+76
-0
src/db/internal/statements.h
src/db/internal/statements.h
+46
-0
src/db/main-db-p.h
src/db/main-db-p.h
+15
-0
src/db/main-db.cpp
src/db/main-db.cpp
+161
-185
src/db/main-db.h
src/db/main-db.h
+6
-0
No files found.
src/CMakeLists.txt
View file @
0c7956d5
...
...
@@ -272,15 +272,12 @@ set(LINPHONE_OBJC_SOURCE_FILES)
if
(
APPLE
)
list
(
APPEND LINPHONE_OBJC_SOURCE_FILES core/paths/paths-apple.mm
)
list
(
APPEND LINPHONE_CXX_OBJECTS_PRIVATE_HEADER_FILES core/paths/paths-apple.h
)
elseif
(
ANDROID
)
list
(
APPEND LINPHONE_CXX_OBJECTS_SOURCE_FILES core/paths/paths-android.cpp core/platform-helpers/android-platform-helpers.cpp
)
list
(
APPEND LINPHONE_CXX_OBJECTS_PRIVATE_HEADER_FILES core/paths/paths-android.h
)
elseif
(
WIN32
)
list
(
APPEND LINPHONE_CXX_OBJECTS_SOURCE_FILES core/paths/paths-windows.cpp
)
list
(
APPEND LINPHONE_CXX_OBJECTS_PRIVATE_HEADER_FILES core/paths/paths-windows.h
)
elseif
(
UNIX
)
list
(
APPEND LINPHONE_CXX_OBJECTS_SOURCE_FILES core/paths/paths-linux.cpp
)
list
(
APPEND LINPHONE_CXX_OBJECTS_PRIVATE_HEADER_FILES core/paths/paths-linux.h
)
...
...
@@ -293,6 +290,15 @@ 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/safe-transaction.h
db/internal/statements.h
)
list
(
APPEND LINPHONE_CXX_OBJECTS_SOURCE_FILES
db/internal/statements.cpp
)
endif
()
set
(
LINPHONE_PRIVATE_HEADER_FILES
)
...
...
src/chat/chat-message/chat-message-p.h
View file @
0c7956d5
...
...
@@ -69,14 +69,20 @@ public:
void
setImdnMessageId
(
const
std
::
string
&
imdnMessageId
);
inline
void
forceFromAddress
(
const
IdentityAddress
&
fromAddress
)
{
void
forceFromAddress
(
const
IdentityAddress
&
fromAddress
)
{
this
->
fromAddress
=
fromAddress
;
}
inline
void
forceToAddress
(
const
IdentityAddress
&
toAddress
)
{
void
forceToAddress
(
const
IdentityAddress
&
toAddress
)
{
this
->
toAddress
=
toAddress
;
}
void
markContentsAsNotLoaded
()
{
contentsNotLoadedFromDatabase
=
true
;
}
void
loadContentsFromDatabase
()
const
;
belle_http_request_t
*
getHttpRequest
()
const
;
void
setHttpRequest
(
belle_http_request_t
*
request
);
...
...
@@ -142,7 +148,7 @@ private:
std
::
string
imdnId
;
std
::
string
rttMessage
;
bool
isSecured
=
false
;
bool
isReadOnly
=
false
;
mutable
bool
isReadOnly
=
false
;
std
::
list
<
Content
*
>
contents
;
Content
internalContent
;
std
::
unordered_map
<
std
::
string
,
std
::
string
>
customHeaders
;
...
...
@@ -176,6 +182,7 @@ private:
bool
encryptionPrevented
=
false
;
bool
toBeStored
=
true
;
mutable
bool
contentsNotLoadedFromDatabase
=
false
;
L_DECLARE_PUBLIC
(
ChatMessage
);
};
...
...
src/chat/chat-message/chat-message.cpp
View file @
0c7956d5
...
...
@@ -183,6 +183,7 @@ string ChatMessagePrivate::getSalCustomHeaderValue (const string &name) {
// -----------------------------------------------------------------------------
bool
ChatMessagePrivate
::
hasTextContent
()
const
{
loadContentsFromDatabase
();
for
(
const
Content
*
c
:
contents
)
{
if
(
c
->
getContentType
()
==
ContentType
::
PlainText
)
{
return
true
;
...
...
@@ -192,6 +193,7 @@ bool ChatMessagePrivate::hasTextContent() const {
}
const
Content
*
ChatMessagePrivate
::
getTextContent
()
const
{
loadContentsFromDatabase
();
for
(
const
Content
*
c
:
contents
)
{
if
(
c
->
getContentType
()
==
ContentType
::
PlainText
)
{
return
c
;
...
...
@@ -201,6 +203,7 @@ const Content* ChatMessagePrivate::getTextContent() const {
}
bool
ChatMessagePrivate
::
hasFileTransferContent
()
const
{
loadContentsFromDatabase
();
for
(
const
Content
*
c
:
contents
)
{
if
(
c
->
getContentType
()
==
ContentType
::
FileTransfer
)
{
return
true
;
...
...
@@ -227,6 +230,7 @@ void ChatMessagePrivate::setFileTransferFilepath (const string &path) {
}
const
string
&
ChatMessagePrivate
::
getAppdata
()
const
{
loadContentsFromDatabase
();
for
(
const
Content
*
c
:
contents
)
{
if
(
c
->
isFile
())
{
FileContent
*
fileContent
=
(
FileContent
*
)
c
;
...
...
@@ -237,6 +241,7 @@ const string &ChatMessagePrivate::getAppdata () const {
}
void
ChatMessagePrivate
::
setAppdata
(
const
string
&
data
)
{
loadContentsFromDatabase
();
for
(
const
Content
*
c
:
contents
)
{
if
(
c
->
isFile
())
{
FileContent
*
fileContent
=
(
FileContent
*
)
c
;
...
...
@@ -256,6 +261,7 @@ const string &ChatMessagePrivate::getExternalBodyUrl () const {
}
const
ContentType
&
ChatMessagePrivate
::
getContentType
()
{
loadContentsFromDatabase
();
if
(
direction
==
ChatMessage
::
Direction
::
Incoming
)
{
if
(
contents
.
size
()
>
0
)
{
Content
*
content
=
contents
.
front
();
...
...
@@ -277,6 +283,7 @@ const ContentType &ChatMessagePrivate::getContentType () {
}
void
ChatMessagePrivate
::
setContentType
(
const
ContentType
&
contentType
)
{
loadContentsFromDatabase
();
if
(
contents
.
size
()
>
0
&&
internalContent
.
getContentType
().
isEmpty
()
&&
internalContent
.
isEmpty
())
{
internalContent
.
setBody
(
contents
.
front
()
->
getBody
());
}
...
...
@@ -290,6 +297,7 @@ void ChatMessagePrivate::setContentType (const ContentType &contentType) {
}
const
string
&
ChatMessagePrivate
::
getText
()
{
loadContentsFromDatabase
();
if
(
direction
==
ChatMessage
::
Direction
::
Incoming
)
{
if
(
hasTextContent
())
{
cText
=
getTextContent
()
->
getBodyAsString
();
...
...
@@ -313,6 +321,7 @@ const string &ChatMessagePrivate::getText () {
}
void
ChatMessagePrivate
::
setText
(
const
string
&
text
)
{
loadContentsFromDatabase
();
if
(
contents
.
size
()
>
0
&&
internalContent
.
getContentType
().
isEmpty
()
&&
internalContent
.
isEmpty
())
{
internalContent
.
setContentType
(
contents
.
front
()
->
getContentType
());
}
...
...
@@ -356,6 +365,7 @@ void ChatMessagePrivate::setFileTransferInformation (const LinphoneContent *c_co
bool
ChatMessagePrivate
::
downloadFile
()
{
L_Q
();
loadContentsFromDatabase
();
for
(
auto
&
content
:
contents
)
if
(
content
->
getContentType
()
==
ContentType
::
FileTransfer
)
...
...
@@ -887,6 +897,18 @@ void ChatMessagePrivate::setImdnMessageId (const string &id) {
imdnId
=
id
;
}
void
ChatMessagePrivate
::
loadContentsFromDatabase
()
const
{
L_Q
();
if
(
contentsNotLoadedFromDatabase
)
{
isReadOnly
=
false
;
contentsNotLoadedFromDatabase
=
false
;
q
->
getChatRoom
()
->
getCore
()
->
getPrivate
()
->
mainDb
->
loadChatMessageContents
(
const_pointer_cast
<
ChatMessage
>
(
q
->
getSharedFromThis
())
);
isReadOnly
=
true
;
}
}
bool
ChatMessage
::
isRead
()
const
{
L_D
();
...
...
@@ -939,6 +961,7 @@ bool ChatMessage::isReadOnly () const {
const
list
<
Content
*>
&
ChatMessage
::
getContents
()
const
{
L_D
();
d
->
loadContentsFromDatabase
();
return
d
->
contents
;
}
...
...
@@ -1000,6 +1023,7 @@ void ChatMessage::send () {
return
;
}
d
->
loadContentsFromDatabase
();
getChatRoom
()
->
getPrivate
()
->
sendChatMessage
(
getSharedFromThis
());
}
...
...
@@ -1039,9 +1063,9 @@ void ChatMessage::cancelFileTransfer () {
int
ChatMessage
::
putCharacter
(
uint32_t
character
)
{
L_D
();
static
const
uint32_t
new
_l
ine
=
0x2028
;
static
const
uint32_t
crlf
=
0x0D0A
;
static
const
uint32_t
lf
=
0x0A
;
const
expr
uint32_t
new
L
ine
=
0x2028
;
const
expr
uint32_t
crlf
=
0x0D0A
;
const
expr
uint32_t
lf
=
0x0A
;
shared_ptr
<
AbstractChatRoom
>
chatRoom
=
getChatRoom
();
if
(
!
(
chatRoom
->
getCapabilities
()
&
LinphonePrivate
::
ChatRoom
::
Capabilities
::
RealTimeText
))
...
...
@@ -1056,7 +1080,7 @@ int ChatMessage::putCharacter (uint32_t character) {
if
(
!
call
||
!
call
->
getPrivate
()
->
getMediaStream
(
LinphoneStreamTypeText
))
return
-
1
;
if
(
character
==
new
_l
ine
||
character
==
crlf
||
character
==
lf
)
{
if
(
character
==
new
L
ine
||
character
==
crlf
||
character
==
lf
)
{
shared_ptr
<
Core
>
core
=
getCore
();
if
(
lp_config_get_int
(
core
->
getCCore
()
->
config
,
"misc"
,
"store_rtt_messages"
,
1
)
==
1
)
{
// TODO: History.
...
...
src/db/internal/safe-transaction.h
0 → 100644
View file @
0c7956d5
/*
* safe-transaction.h
* Copyright (C) 2010-2018 Belledonne Communications SARL
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#ifndef _L_SAFE_TRANSACTION_H_
#define _L_SAFE_TRANSACTION_H_
#include <soci/soci.h>
#include "db/main-db.h"
#include "logger/logger.h"
// =============================================================================
#define L_SAFE_TRANSACTION_C(CONTEXT) \
LinphonePrivate::SafeTransactionInfo().set(__func__, CONTEXT) * [&]()
#define L_SAFE_TRANSACTION L_SAFE_TRANSACTION_C(this)
LINPHONE_BEGIN_NAMESPACE
struct
SafeTransactionInfo
{
SafeTransactionInfo
&
set
(
const
char
*
_name
,
const
MainDb
*
_mainDb
)
{
name
=
_name
;
mainDb
=
const_cast
<
MainDb
*>
(
_mainDb
);
return
*
this
;
}
const
char
*
name
=
nullptr
;
MainDb
*
mainDb
=
nullptr
;
};
template
<
typename
Function
>
class
SafeTransaction
{
using
InternalReturnType
=
typename
std
::
remove_reference
<
decltype
(
std
::
declval
<
Function
>
()())
>::
type
;
public:
using
ReturnType
=
typename
std
::
conditional
<
std
::
is_same
<
InternalReturnType
,
void
>::
value
,
bool
,
InternalReturnType
>::
type
;
SafeTransaction
(
SafeTransactionInfo
&
info
,
Function
function
)
:
mFunction
(
std
::
move
(
function
))
{
try
{
mResult
=
exec
<
InternalReturnType
>
();
}
catch
(
const
soci
::
soci_error
&
e
)
{
lWarning
()
<<
"Catched exception in MainDb::"
<<
info
.
name
<<
"("
<<
e
.
what
()
<<
")."
;
soci
::
soci_error
::
error_category
category
=
e
.
get_error_category
();
if
(
(
category
==
soci
::
soci_error
::
connection_error
||
category
==
soci
::
soci_error
::
unknown
)
&&
info
.
mainDb
->
forceReconnect
()
)
{
try
{
mResult
=
exec
<
InternalReturnType
>
();
}
catch
(
const
std
::
exception
&
e
)
{
lError
()
<<
"Unable to execute query after reconnect in MainDb::"
<<
info
.
name
<<
"("
<<
e
.
what
()
<<
")."
;
}
return
;
}
lError
()
<<
"Unhandled ["
<<
getErrorCategoryAsString
(
category
)
<<
"] exception in MainDb::"
<<
info
.
name
<<
": `"
<<
e
.
what
()
<<
"`."
;
}
catch
(
const
std
::
exception
&
e
)
{
lError
()
<<
"Unhandled generic exception in MainDb::"
<<
info
.
name
<<
": `"
<<
e
.
what
()
<<
"`."
;
}
}
SafeTransaction
(
SafeTransaction
&&
safeTransaction
)
:
mFunction
(
std
::
move
(
safeTransaction
.
mFunction
))
{}
operator
ReturnType
()
const
{
return
mResult
;
}
private:
// Exec function with no return type.
template
<
typename
T
>
typename
std
::
enable_if
<
std
::
is_same
<
T
,
void
>::
value
,
bool
>::
type
exec
()
const
{
mFunction
();
return
true
;
}
// Exec function with return type.
template
<
typename
T
>
typename
std
::
enable_if
<!
std
::
is_same
<
T
,
void
>::
value
,
T
>::
type
exec
()
const
{
return
mFunction
();
}
static
const
char
*
getErrorCategoryAsString
(
soci
::
soci_error
::
error_category
category
)
{
switch
(
category
)
{
case
soci
::
soci_error
::
connection_error
:
return
"CONNECTION ERROR"
;
case
soci
::
soci_error
::
invalid_statement
:
return
"INVALID STATEMENT"
;
case
soci
::
soci_error
::
no_privilege
:
return
"NO PRIVILEGE"
;
case
soci
::
soci_error
::
no_data
:
return
"NO DATA"
;
case
soci
::
soci_error
::
constraint_violation
:
return
"CONSTRAINT VIOLATION"
;
case
soci
::
soci_error
::
unknown_transaction_state
:
return
"UNKNOWN TRANSACTION STATE"
;
case
soci
::
soci_error
::
system_error
:
return
"SYSTEM ERROR"
;
case
soci
::
soci_error
::
unknown
:
return
"UNKNOWN"
;
}
// Unreachable.
L_ASSERT
(
false
);
return
nullptr
;
}
Function
mFunction
;
ReturnType
mResult
{};
L_DISABLE_COPY
(
SafeTransaction
);
};
template
<
typename
Function
>
typename
SafeTransaction
<
Function
>::
ReturnType
operator
*
(
SafeTransactionInfo
&
info
,
Function
&&
function
)
{
return
SafeTransaction
<
Function
>
(
info
,
std
::
forward
<
Function
>
(
function
));
}
LINPHONE_END_NAMESPACE
#endif // ifndef _L_SAFE_TRANSACTION_H_
src/db/internal/statements.cpp
0 → 100644
View file @
0c7956d5
/*
* statements.cpp
* Copyright (C) 2010-2018 Belledonne Communications SARL
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "statements.h"
// =============================================================================
LINPHONE_BEGIN_NAMESPACE
namespace
Statements
{
// ---------------------------------------------------------------------------
// Create statements.
// ---------------------------------------------------------------------------
constexpr
const
char
*
create
[
CreateCount
]
=
{
[
CreateConferenceEventView
]
=
R"(
CREATE TEMP 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
const
char
*
select
[
SelectCount
]
=
{
[
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
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 chat_room_id = :chatRoomId
)"
};
// ---------------------------------------------------------------------------
// Getters.
// ---------------------------------------------------------------------------
const
char
*
get
(
Create
createStmt
,
AbstractDb
::
Backend
backend
)
{
(
void
)
backend
;
return
createStmt
>=
Create
::
CreateCount
?
nullptr
:
create
[
createStmt
];
}
const
char
*
get
(
Select
selectStmt
,
AbstractDb
::
Backend
backend
)
{
(
void
)
backend
;
return
selectStmt
>=
Select
::
SelectCount
?
nullptr
:
select
[
selectStmt
];
}
}
LINPHONE_END_NAMESPACE
src/db/internal/statements.h
0 → 100644
View file @
0c7956d5
/*
* statements.h
* Copyright (C) 2010-2018 Belledonne Communications SARL
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#ifndef _L_STATEMENTS_H_
#define _L_STATEMENTS_H_
#include "db/abstract/abstract-db.h"
// =============================================================================
LINPHONE_BEGIN_NAMESPACE
namespace
Statements
{
enum
Create
{
CreateConferenceEventView
,
CreateCount
};
enum
Select
{
SelectConferenceEvents
,
SelectCount
};
const
char
*
get
(
Create
createStmt
,
AbstractDb
::
Backend
backend
);
const
char
*
get
(
Select
selectStmt
,
AbstractDb
::
Backend
backend
);
}
LINPHONE_END_NAMESPACE
#endif // ifndef _L_STATEMENTS_H_
src/db/main-db-p.h
View file @
0c7956d5
...
...
@@ -103,6 +103,21 @@ private:
const
ChatRoomId
&
chatRoomId
)
const
;
// TODO: Remove me. Workaround to increase fetch performance.
std
::
shared_ptr
<
EventLog
>
selectConferenceChatMessageEvent
(
long
long
eventId
,
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
;
std
::
shared_ptr
<
EventLog
>
selectConferenceParticipantEvent
(
long
long
eventId
,
EventLog
::
Type
type
,
...
...
src/db/main-db.cpp
View file @
0c7956d5
...
...
@@ -36,6 +36,11 @@
#include "main-db-key-p.h"
#include "main-db-p.h"
#ifdef SOCI_ENABLED
#include "internal/safe-transaction.h"
#include "internal/statements.h"
#endif // ifdef SOCI_ENABLED
// =============================================================================
// See: http://soci.sourceforge.net/doc/3.2/exchange.html
...
...
@@ -88,117 +93,6 @@ MainDb::MainDb (const shared_ptr<Core> &core) : AbstractDb(*new MainDbPrivate),
#ifdef SOCI_ENABLED
// -----------------------------------------------------------------------------
// Errors handling.
// -----------------------------------------------------------------------------
#define L_SAFE_TRANSACTION_C(CONTEXT) \
LinphonePrivate::SafeTransactionInfo().set(__func__, CONTEXT) * [&]()
#define L_SAFE_TRANSACTION L_SAFE_TRANSACTION_C(this)
struct
SafeTransactionInfo
{
SafeTransactionInfo
&
set
(
const
char
*
_name
,
const
MainDb
*
_mainDb
)
{
name
=
_name
;
mainDb
=
const_cast
<
MainDb
*>
(
_mainDb
);
return
*
this
;
}
const
char
*
name
=
nullptr
;
MainDb
*
mainDb
=
nullptr
;
};
template
<
typename
Function
>
class
SafeTransaction
{
using
InternalReturnType
=
typename
remove_reference
<
decltype
(
declval
<
Function
>
()())
>::
type
;
public:
using
ReturnType
=
typename
std
::
conditional
<
std
::
is_same
<
InternalReturnType
,
void
>::
value
,
bool
,
InternalReturnType
>::
type
;
SafeTransaction
(
SafeTransactionInfo
&
info
,
Function
function
)
:
mFunction
(
move
(
function
))
{
try
{
mResult
=
exec
<
InternalReturnType
>
();
}
catch
(
const
soci
::
soci_error
&
e
)
{
lWarning
()
<<
"Catched exception in MainDb::"
<<
info
.
name
<<
"("
<<
e
.
what
()
<<
")."
;
soci
::
soci_error
::
error_category
category
=
e
.
get_error_category
();
if
(
(
category
==
soci
::
soci_error
::
connection_error
||
category
==
soci
::
soci_error
::
unknown
)
&&
info
.
mainDb
->
forceReconnect
()
)
{
try
{
mResult
=
exec
<
InternalReturnType
>
();
}
catch
(
const
exception
&
e
)
{
lError
()
<<
"Unable to execute query after reconnect in MainDb::"
<<
info
.
name
<<
"("
<<
e
.
what
()
<<
")."
;
}
return
;
}
lError
()
<<
"Unhandled ["
<<
getErrorCategoryAsString
(
category
)
<<
"] exception in MainDb::"
<<
info
.
name
<<
": `"
<<
e
.
what
()
<<
"`."
;
}
catch
(
const
exception
&
e
)
{
lError
()
<<
"Unhandled generic exception in MainDb::"
<<
info
.
name
<<
": `"
<<
e
.
what
()
<<
"`."
;
}
}
SafeTransaction
(
SafeTransaction
&&
safeTransaction
)
:
mFunction
(
move
(
safeTransaction
.
mFunction
))
{}
operator
ReturnType
()
const
{
return
mResult
;
}
private:
// Exec function with no return type.
template
<
typename
T
>
typename
std
::
enable_if
<
std
::
is_same
<
T
,
void
>::
value
,
bool
>::
type
exec
()
const
{
mFunction
();
return
true
;
}
// Exec function with return type.
template
<
typename
T
>
typename
std
::
enable_if
<!
std
::
is_same
<
T
,
void
>::
value
,
T
>::
type
exec
()
const
{
return
mFunction
();
}
static
const
char
*
getErrorCategoryAsString
(
soci
::
soci_error
::
error_category
category
)
{
switch
(
category
)
{
case
soci
::
soci_error
::
connection_error
:
return
"CONNECTION ERROR"
;
case
soci
::
soci_error
::
invalid_statement
:
return
"INVALID STATEMENT"
;
case
soci
::
soci_error
::
no_privilege
:
return
"NO PRIVILEGE"
;
case
soci
::
soci_error
::
no_data
:
return
"NO DATA"
;
case
soci
::
soci_error
::
constraint_violation
:
return
"CONSTRAINT VIOLATION"
;
case
soci
::
soci_error
::
unknown_transaction_state
:
return
"UNKNOWN TRANSACTION STATE"
;
case
soci
::
soci_error
::
system_error
:
return
"SYSTEM ERROR"
;
case
soci
::
soci_error
::
unknown
:
return
"UNKNOWN"
;
}
// Unreachable.
L_ASSERT
(
false
);
return
nullptr
;
}
Function
mFunction
;
ReturnType
mResult
{};
L_DISABLE_COPY
(
SafeTransaction
);
};
template
<
typename
Function
>
typename
SafeTransaction
<
Function
>::
ReturnType
operator
*
(
SafeTransactionInfo
&
info
,
Function
&&
function
)
{
return
SafeTransaction
<
Function
>
(
info
,
forward
<
Function
>
(
function
));
}
// -----------------------------------------------------------------------------
//