1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
|
/*
* Copyright (C) 2008-2016 TrinityCore <http://www.trinitycore.org/>
*
* 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, see <http://www.gnu.org/licenses/>.
*/
#include "DatabaseWorkerPool.h"
#include "Transaction.h"
#include "Util.h"
#include "ProducerConsumerQueue.h"
#ifndef _MYSQLCONNECTION_H
#define _MYSQLCONNECTION_H
class DatabaseWorker;
class PreparedStatement;
class MySQLPreparedStatement;
class PingOperation;
enum ConnectionFlags
{
CONNECTION_ASYNC = 0x1,
CONNECTION_SYNCH = 0x2,
CONNECTION_BOTH = CONNECTION_ASYNC | CONNECTION_SYNCH
};
struct MySQLConnectionInfo
{
explicit MySQLConnectionInfo(std::string const& infoString)
{
Tokenizer tokens(infoString, ';');
if (tokens.size() != 5)
return;
uint8 i = 0;
host.assign(tokens[i++]);
port_or_socket.assign(tokens[i++]);
user.assign(tokens[i++]);
password.assign(tokens[i++]);
database.assign(tokens[i++]);
}
std::string user;
std::string password;
std::string database;
std::string host;
std::string port_or_socket;
};
typedef std::map<uint32 /*index*/, std::pair<std::string /*query*/, ConnectionFlags /*sync/async*/> > PreparedStatementMap;
class MySQLConnection
{
template <class T> friend class DatabaseWorkerPool;
friend class PingOperation;
public:
MySQLConnection(MySQLConnectionInfo& connInfo); //! Constructor for synchronous connections.
MySQLConnection(ProducerConsumerQueue<SQLOperation*>* queue, MySQLConnectionInfo& connInfo); //! Constructor for asynchronous connections.
virtual ~MySQLConnection();
virtual uint32 Open();
void Close();
bool PrepareStatements();
public:
bool Execute(const char* sql);
bool Execute(PreparedStatement* stmt);
ResultSet* Query(const char* sql);
PreparedResultSet* Query(PreparedStatement* stmt);
bool _Query(const char *sql, MYSQL_RES **pResult, MYSQL_FIELD **pFields, uint64* pRowCount, uint32* pFieldCount);
bool _Query(PreparedStatement* stmt, MYSQL_RES **pResult, uint64* pRowCount, uint32* pFieldCount);
void BeginTransaction();
void RollbackTransaction();
void CommitTransaction();
int ExecuteTransaction(SQLTransaction& transaction);
operator bool () const { return m_Mysql != NULL; }
void Ping() { mysql_ping(m_Mysql); }
uint32 GetLastError() { return mysql_errno(m_Mysql); }
protected:
bool LockIfReady()
{
/// Tries to acquire lock. If lock is acquired by another thread
/// the calling parent will just try another connection
return m_Mutex.try_lock();
}
void Unlock()
{
/// Called by parent databasepool. Will let other threads access this connection
m_Mutex.unlock();
}
MYSQL* GetHandle() { return m_Mysql; }
MySQLPreparedStatement* GetPreparedStatement(uint32 index);
void PrepareStatement(uint32 index, const char* sql, ConnectionFlags flags);
virtual void DoPrepareStatements() = 0;
protected:
std::vector<std::unique_ptr<MySQLPreparedStatement>> m_stmts; //! PreparedStatements storage
PreparedStatementMap m_queries; //! Query storage
bool m_reconnecting; //! Are we reconnecting?
bool m_prepareError; //! Was there any error while preparing statements?
private:
bool _HandleMySQLErrno(uint32 errNo, uint8 attempts = 5);
private:
ProducerConsumerQueue<SQLOperation*>* m_queue; //! Queue shared with other asynchronous connections.
std::unique_ptr<DatabaseWorker> m_worker; //! Core worker task.
MYSQL* m_Mysql; //! MySQL Handle.
MySQLConnectionInfo& m_connectionInfo; //! Connection info (used for logging)
ConnectionFlags m_connectionFlags; //! Connection flags (for preparing relevant statements)
std::mutex m_Mutex;
MySQLConnection(MySQLConnection const& right) = delete;
MySQLConnection& operator=(MySQLConnection const& right) = delete;
};
#endif
|