-
Notifications
You must be signed in to change notification settings - Fork 345
/
mythdbcon.h
230 lines (187 loc) · 7.57 KB
/
mythdbcon.h
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
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
#ifndef MYTHDBCON_H_
#define MYTHDBCON_H_
#include <QSqlDatabase>
#include <QSqlRecord>
#include <QSqlError>
#include <QVariant>
#include <QSqlQuery>
#include <QRegExp>
#include <QDateTime>
#include <QMutex>
#include <QList>
#include "mythbaseexp.h"
#include "mythdbparams.h"
#define REUSE_CONNECTION 1
MBASE_PUBLIC bool TestDatabase(QString dbHostName,
QString dbUserName,
QString dbPassword,
QString dbName = "mythconverg",
int dbPort = 3306);
/// \brief QSqlDatabase wrapper, used by MSqlQuery. Do not use directly.
class MSqlDatabase
{
friend class MDBManager;
friend class MSqlQuery;
public:
MSqlDatabase(const QString &name);
~MSqlDatabase(void);
bool OpenDatabase(bool skipdb = false);
void SetDBParams(DatabaseParams params) { m_dbparms = params; };
private:
bool isOpen(void);
bool KickDatabase(void);
QString GetConnectionName(void) const { return m_name; }
QSqlDatabase db(void) const { return m_db; }
bool Reconnect(void);
private:
QString m_name;
QSqlDatabase m_db;
QDateTime m_lastDBKick;
DatabaseParams m_dbparms;
};
/// \brief DB connection pool, used by MSqlQuery. Do not use directly.
class MBASE_PUBLIC MDBManager
{
friend class MSqlQuery;
public:
MDBManager(void);
~MDBManager(void);
void CloseDatabases(void);
void PurgeIdleConnections(bool leaveOne = false);
protected:
MSqlDatabase *popConnection(bool reuse);
void pushConnection(MSqlDatabase *db);
MSqlDatabase *getSchedCon(void);
MSqlDatabase *getDDCon(void);
private:
MSqlDatabase *getStaticCon(MSqlDatabase **dbcon, QString name);
QMutex m_lock;
typedef QList<MSqlDatabase*> DBList;
QHash<QThread*, DBList> m_pool; // protected by m_lock
#if REUSE_CONNECTION
QHash<QThread*, MSqlDatabase*> m_inuse; // protected by m_lock
QHash<QThread*, int> m_inuse_count; // protected by m_lock
#endif
int m_nextConnID;
int m_connCount;
MSqlDatabase *m_schedCon;
MSqlDatabase *m_DDCon;
QHash<QThread*, DBList> m_static_pool;
};
/// \brief MSqlDatabase Info, used by MSqlQuery. Do not use directly.
typedef struct _MSqlQueryInfo
{
MSqlDatabase *db;
QSqlDatabase qsqldb;
bool returnConnection;
} MSqlQueryInfo;
/// \brief typedef for a map of string -> string bindings for generic queries.
typedef QMap<QString, QVariant> MSqlBindings;
/// \brief Add the entries in addfrom to the map in output
MBASE_PUBLIC void MSqlAddMoreBindings(MSqlBindings &output, MSqlBindings &addfrom);
/// \brief Given a partial query string and a bindings object, escape the string
MBASE_PUBLIC void MSqlEscapeAsAQuery(QString &query, MSqlBindings &bindings);
/** \brief QSqlQuery wrapper that fetches a DB connection from the connection pool.
*
* Myth & database connections
* Rule #1: Never use QSqlQuery or QSqlDatabase directly.
* Rule #2: Never use QSqlQuery or QSqlDatabase directly.
* Rule #3: Use MSqlQuery for all DB stuff.
*
* MSqlQuery is tied to a connection pool in MythContext. DB connections are
* automatically set up by creating an MSqlQuery object. Use the helper
* functions to create an MSqlQuery object e.g.
* MSqlQuery query(MSqlQuery::InitCon());
* The MSqlQuery object gets exclusive access to the connection for its
* lifetime. The connection is automatically returned when the MSqlQuery
* object is destroyed.
*
* Note: Due to a bug in some Qt/MySql combinations, QSqlDatabase connections
* will crash if closed and reopend - so we never close them and keep them in
* a pool.
*/
class MBASE_PUBLIC MSqlQuery : private QSqlQuery
{
MBASE_PUBLIC friend void MSqlEscapeAsAQuery(QString&, MSqlBindings&);
public:
/// \brief Get DB connection from pool
MSqlQuery(const MSqlQueryInfo &qi);
/// \brief Returns conneciton to pool
~MSqlQuery();
/// \brief Only updated once during object creation
bool isConnected(void) { return m_isConnected; }
/// \brief Wrap QSqlQuery::exec() so we can display SQL
bool exec(void);
/// \brief Wrap QSqlQuery::next() so we can display the query results
bool next(void);
/// \brief Wrap QSqlQuery::previous() so we can display the query results
bool previous(void);
/// \brief Wrap QSqlQuery::first() so we can display the query results
bool first(void);
/// \brief Wrap QSqlQuery::last() so we can display the query results
bool last(void);
/// \brief Wrap QSqlQuery::seek(int,bool)
// so we can display the query results
bool seek(int, bool relative = false);
/// \brief Wrap QSqlQuery::exec(const QString &query) so we can display SQL
bool exec(const QString &query);
/// \brief QSqlQuery::prepare() is not thread safe in Qt <= 3.3.2
bool prepare(const QString &query);
void bindValue(const QString &placeholder, const QVariant &val);
/// \brief Add all the bindings in the passed in bindings
void bindValues(const MSqlBindings &bindings);
/** \brief Return the id of the last inserted row
*
* Note: Currently, this function is only implemented in Qt4 (in QSqlQuery
* and QSqlResult), and is implemented here until the switch to Qt4. Also,
* the current implementation will only work for a DBMS that supports
* the function LAST_INSERT_ID() (i.e. MySQL), and will _not_ work
* in SQLite.
*/
QVariant lastInsertId();
/// Reconnects server and re-prepares and re-binds the last prepared
/// query.
bool Reconnect(void);
// Thunks that allow us to make QSqlQuery private
QVariant value(int i) const { return QSqlQuery::value(i); }
QString executedQuery(void) const { return QSqlQuery::executedQuery(); }
QMap<QString, QVariant> boundValues(void) const
{ return QSqlQuery::boundValues(); }
QSqlError lastError(void) const { return QSqlQuery::lastError(); }
int size(void) const { return QSqlQuery::size();}
bool isActive(void) const { return QSqlQuery::isActive(); }
QSqlRecord record(void) const { return QSqlQuery::record(); }
int numRowsAffected() const { return QSqlQuery::numRowsAffected(); }
void setForwardOnly(bool f) { QSqlQuery::setForwardOnly(f); }
bool isNull(int field) const { return QSqlQuery::isNull(field); }
const QSqlDriver *driver(void) const { return QSqlQuery::driver(); }
int at(void) const { return QSqlQuery::at(); }
/// \brief Checks DB connection + login (login info via Mythcontext)
static bool testDBConnection();
typedef enum
{
kDedicatedConnection,
kNormalConnection,
} ConnectionReuse;
/// \brief Only use this in combination with MSqlQuery constructor
static MSqlQueryInfo InitCon(ConnectionReuse = kNormalConnection);
/// \brief Returns dedicated connection. (Required for using temporary SQL tables.)
static MSqlQueryInfo SchedCon();
/// \brief Returns dedicated connection. (Required for using temporary SQL tables.)
static MSqlQueryInfo DDCon();
private:
// Only QSql::In is supported as a param type and only named params...
void bindValue(const QString&, const QVariant&, QSql::ParamType);
void bindValue(int, const QVariant&, QSql::ParamType);
void addBindValue(const QVariant&, QSql::ParamType = QSql::In);
bool seekDebug(const char *type, bool result,
int where, bool relative) const;
MSqlDatabase *m_db;
bool m_isConnected;
bool m_returnConnection;
QString m_last_prepared_query; // holds a copy of the last prepared query
#ifdef DEBUG_QT4_PORT
QRegExp m_testbindings;
#endif
};
#endif