1 /*****************************************************************************
2 * PokerTH - The open source texas holdem engine *
3 * Copyright (C) 2006-2016 Felix Hammer, Florian Thauer, Lothar May *
4 * *
5 * This program is free software: you can redistribute it and/or modify *
6 * it under the terms of the GNU Affero General Public License as *
7 * published by the Free Software Foundation, either version 3 of the *
8 * License, or (at your option) any later version. *
9 * *
10 * This program is distributed in the hope that it will be useful, *
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
13 * GNU Affero General Public License for more details. *
14 * *
15 * You should have received a copy of the GNU Affero General Public License *
16 * along with this program. If not, see <http://www.gnu.org/licenses/>. *
17 * *
18 * *
19 * Additional permission under GNU AGPL version 3 section 7 *
20 * *
21 * If you modify this program, or any covered work, by linking or *
22 * combining it with the OpenSSL project's OpenSSL library (or a *
23 * modified version of that library), containing parts covered by the *
24 * terms of the OpenSSL or SSLeay licenses, the authors of PokerTH *
25 * (Felix Hammer, Florian Thauer, Lothar May) grant you additional *
26 * permission to convey the resulting work. *
27 * Corresponding Source for a non-source form of such a combination *
28 * shall include the source code for the parts of OpenSSL used as well *
29 * as that of the covered work. *
30 *****************************************************************************/
31
32 #include <dbofficial/serverdbthread.h>
33 #include <dbofficial/asyncdbauth.h>
34 #include <dbofficial/asyncdblogin.h>
35 #include <dbofficial/asyncdbavatarblacklist.h>
36 #include <dbofficial/asyncdbcreategame.h>
37 #include <dbofficial/asyncdbendgame.h>
38 #include <dbofficial/asyncdbgameplace.h>
39 #include <dbofficial/asyncdbupdatescore.h>
40 #include <dbofficial/asyncdbreportavatar.h>
41 #include <dbofficial/asyncdbreportgame.h>
42 #include <dbofficial/asyncdbadminplayers.h>
43 #include <dbofficial/asyncdbblockplayer.h>
44 #include <dbofficial/compositeasyncdbquery.h>
45 #include <dbofficial/db_table_defs.h>
46 #include <ctime>
47 #include <sstream>
48 #include <mysql++.h>
49
50 #define QUERY_NICK_PREPARE "nick_template"
51 #define QUERY_LOGIN_PREPARE "login_template"
52 #define QUERY_AVATAR_BLACKLIST_PREPARE "avatar_blacklist_template"
53 #define QUERY_CREATE_GAME_PREPARE "create_game_template"
54 #define QUERY_END_GAME_PREPARE "end_game_template"
55 #define QUERY_GAME_PLAYER_PREPARE "game_player_template"
56 #define QUERY_UPDATE_SCORE_PREPARE "update_score_template"
57 #define QUERY_REPORT_AVATAR_PREPARE "report_avatar_template"
58 #define QUERY_REPORT_GAME_PREPARE "report_game_template"
59 #define QUERY_ADMIN_PLAYER_PREPARE "admin_player_template"
60 #define QUERY_BLOCK_PLAYER_PREPARE "block_player_template"
61
62 using namespace std;
63
64 struct DBConnectionData {
DBConnectionDataDBConnectionData65 DBConnectionData() : conn(false) {}
66 string host;
67 string user;
68 string pwd;
69 string database;
70 string encryptionKey;
71 mysqlpp::Connection conn;
72 };
73
ServerDBThread(ServerDBCallback & cb,boost::shared_ptr<boost::asio::io_service> ioService)74 ServerDBThread::ServerDBThread(ServerDBCallback &cb, boost::shared_ptr<boost::asio::io_service> ioService)
75 : m_ioService(ioService), m_semaphore(0), m_callback(cb), m_isConnected(false), m_permanentError(false), m_previouslyConnected(false)
76 {
77 m_connData.reset(new DBConnectionData);
78 }
79
~ServerDBThread()80 ServerDBThread::~ServerDBThread()
81 {
82 }
83
84 void
SignalTermination()85 ServerDBThread::SignalTermination()
86 {
87 Thread::SignalTermination();
88 m_semaphore.post();
89 }
90
91 void
Init(const string & host,const string & user,const string & pwd,const string & database,const string & encryptionKey)92 ServerDBThread::Init(const string &host, const string &user, const string &pwd,
93 const string &database, const string &encryptionKey)
94 {
95 m_connData->host = host;
96 m_connData->user = user;
97 m_connData->pwd = pwd;
98 m_connData->database = database;
99 m_connData->encryptionKey = encryptionKey;
100 }
101
102 void
Start()103 ServerDBThread::Start()
104 {
105 Run();
106 }
107
108 void
Stop()109 ServerDBThread::Stop()
110 {
111 SignalTermination();
112 this->Join(THREAD_WAIT_INFINITE);
113 }
114
115 void
AsyncPlayerLogin(unsigned requestId,const string & playerName)116 ServerDBThread::AsyncPlayerLogin(unsigned requestId, const string &playerName)
117 {
118 if (IsConnected()) {
119 list<string> params;
120 params.push_back(m_connData->encryptionKey);
121 params.push_back(playerName);
122 boost::shared_ptr<AsyncDBQuery> asyncQuery(
123 new AsyncDBAuth(
124 requestId,
125 QUERY_NICK_PREPARE,
126 params));
127
128 {
129 boost::mutex::scoped_lock lock(m_asyncQueueMutex);
130 m_asyncQueue.push(asyncQuery);
131 }
132 m_semaphore.post();
133 } else {
134 // If not connected to database, login fails.
135 m_ioService->post(boost::bind(&ServerDBCallback::PlayerLoginFailed, &m_callback, requestId));
136 }
137 }
138
139 void
AsyncCheckAvatarBlacklist(unsigned requestId,const std::string & avatarHash)140 ServerDBThread::AsyncCheckAvatarBlacklist(unsigned requestId, const std::string &avatarHash)
141 {
142 if (IsConnected()) {
143 list<string> params;
144 params.push_back(avatarHash);
145 boost::shared_ptr<AsyncDBQuery> asyncQuery(
146 new AsyncDBAvatarBlacklist(
147 requestId,
148 QUERY_AVATAR_BLACKLIST_PREPARE,
149 params));
150
151 {
152 boost::mutex::scoped_lock lock(m_asyncQueueMutex);
153 m_asyncQueue.push(asyncQuery);
154 }
155 m_semaphore.post();
156 } else {
157 // If not connected to database, all avatars are blacklisted.
158 m_ioService->post(boost::bind(&ServerDBCallback::AvatarIsBlacklisted, &m_callback, requestId));
159 }
160 }
161
162 void
PlayerPostLogin(DB_id playerId,const std::string & avatarHash,const std::string & avatarType)163 ServerDBThread::PlayerPostLogin(DB_id playerId, const std::string &avatarHash, const std::string &avatarType)
164 {
165 list<string> params;
166 params.push_back(mysqlpp::DateTime(time(NULL)));
167 params.push_back(avatarHash);
168 params.push_back(avatarType);
169 ostringstream paramStream;
170 paramStream << playerId;
171 params.push_back(paramStream.str());
172 boost::shared_ptr<AsyncDBQuery> asyncQuery(
173 new AsyncDBLogin(
174 playerId,
175 QUERY_LOGIN_PREPARE,
176 params));
177
178 {
179 boost::mutex::scoped_lock lock(m_asyncQueueMutex);
180 m_asyncQueue.push(asyncQuery);
181 }
182 m_semaphore.post();
183 }
184
185 void
PlayerLogout(DB_id)186 ServerDBThread::PlayerLogout(DB_id /*playerId*/)
187 {
188 }
189
190 void
AsyncCreateGame(unsigned requestId,const string & gameName)191 ServerDBThread::AsyncCreateGame(unsigned requestId, const string &gameName)
192 {
193 list<string> params;
194 params.push_back(gameName);
195 params.push_back(mysqlpp::DateTime(time(NULL)));
196 boost::shared_ptr<AsyncDBQuery> asyncQuery(
197 new AsyncDBCreateGame(
198 requestId,
199 QUERY_CREATE_GAME_PREPARE,
200 params));
201
202 {
203 boost::mutex::scoped_lock lock(m_asyncQueueMutex);
204 m_asyncQueue.push(asyncQuery);
205 }
206 m_semaphore.post();
207 }
208
209 void
SetGamePlayerPlace(unsigned requestId,DB_id playerId,unsigned place)210 ServerDBThread::SetGamePlayerPlace(unsigned requestId, DB_id playerId, unsigned place)
211 {
212 // The game id param is added later (during init of the async op), because it may be unknown.
213 list<string> params;
214 ostringstream paramStream;
215 paramStream << playerId;
216 params.push_back(paramStream.str());
217 paramStream.str("");
218 paramStream << place;
219 params.push_back(paramStream.str());
220 boost::shared_ptr<AsyncDBQuery> asyncQuery(
221 new AsyncDBGamePlace(
222 requestId,
223 QUERY_GAME_PLAYER_PREPARE,
224 params));
225
226 {
227 boost::mutex::scoped_lock lock(m_asyncQueueMutex);
228 m_asyncQueue.push(asyncQuery);
229 }
230 m_semaphore.post();
231 }
232
233 void
EndGame(unsigned requestId)234 ServerDBThread::EndGame(unsigned requestId)
235 {
236 // Set the end time of the game.
237 {
238 list<string> params;
239 params.push_back(mysqlpp::DateTime(time(NULL)));
240 boost::shared_ptr<AsyncDBQuery> asyncQuery(
241 new AsyncDBEndGame(
242 requestId,
243 QUERY_END_GAME_PREPARE,
244 params));
245
246 {
247 boost::mutex::scoped_lock lock(m_asyncQueueMutex);
248 m_asyncQueue.push(asyncQuery);
249 }
250 m_semaphore.post();
251 }
252 // Update the player scores.
253 {
254 list<string> params;
255 boost::shared_ptr<AsyncDBQuery> asyncQuery(
256 new AsyncDBUpdateScore(
257 requestId,
258 QUERY_UPDATE_SCORE_PREPARE,
259 params));
260
261 {
262 boost::mutex::scoped_lock lock(m_asyncQueueMutex);
263 m_asyncQueue.push(asyncQuery);
264 }
265 m_semaphore.post();
266 }
267 }
268
269 void
AsyncReportAvatar(unsigned requestId,unsigned replyId,DB_id reportedPlayerId,const std::string & avatarHash,const std::string & avatarType,DB_id * byPlayerId)270 ServerDBThread::AsyncReportAvatar(unsigned requestId, unsigned replyId, DB_id reportedPlayerId, const std::string &avatarHash, const std::string &avatarType, DB_id *byPlayerId)
271 {
272 list<string> params;
273 ostringstream paramStream;
274 paramStream << reportedPlayerId;
275 params.push_back(paramStream.str());
276 params.push_back(avatarHash);
277 params.push_back(avatarType);
278 if (byPlayerId) {
279 paramStream.str("");
280 paramStream << *byPlayerId;
281 params.push_back(paramStream.str());
282 } else {
283 params.push_back("NULL");
284 }
285 params.push_back(mysqlpp::DateTime(time(NULL)));
286
287 boost::shared_ptr<AsyncDBQuery> asyncQuery(
288 new AsyncDBReportAvatar(
289 requestId,
290 replyId,
291 QUERY_REPORT_AVATAR_PREPARE,
292 params));
293
294 {
295 boost::mutex::scoped_lock lock(m_asyncQueueMutex);
296 m_asyncQueue.push(asyncQuery);
297 }
298 m_semaphore.post();
299 }
300
301 void
AsyncReportGame(unsigned requestId,unsigned replyId,DB_id * creatorPlayerId,unsigned gameId,const std::string & gameName,DB_id * byPlayerId)302 ServerDBThread::AsyncReportGame(unsigned requestId, unsigned replyId, DB_id *creatorPlayerId, unsigned gameId, const std::string &gameName, DB_id *byPlayerId)
303 {
304 list<string> params;
305 ostringstream paramStream;
306 if (creatorPlayerId) {
307 paramStream << *creatorPlayerId;
308 params.push_back(paramStream.str());
309 } else {
310 params.push_back("NULL");
311 }
312 params.push_back(gameName);
313 if (byPlayerId) {
314 paramStream.str("");
315 paramStream << *byPlayerId;
316 params.push_back(paramStream.str());
317 } else {
318 params.push_back("NULL");
319 }
320 params.push_back(mysqlpp::DateTime(time(NULL)));
321
322 boost::shared_ptr<AsyncDBQuery> asyncQuery(
323 new AsyncDBReportGame(
324 requestId,
325 replyId,
326 gameId,
327 QUERY_REPORT_GAME_PREPARE,
328 params));
329
330 {
331 boost::mutex::scoped_lock lock(m_asyncQueueMutex);
332 m_asyncQueue.push(asyncQuery);
333 }
334
335 m_semaphore.post();
336 }
337
338 void
AsyncQueryAdminPlayers(unsigned requestId)339 ServerDBThread::AsyncQueryAdminPlayers(unsigned requestId)
340 {
341 boost::shared_ptr<AsyncDBQuery> asyncQuery(
342 new AsyncDBAdminPlayers(
343 requestId,
344 QUERY_ADMIN_PLAYER_PREPARE));
345 {
346 boost::mutex::scoped_lock lock(m_asyncQueueMutex);
347 m_asyncQueue.push(asyncQuery);
348 }
349
350 m_semaphore.post();
351 }
352
353 void
AsyncBlockPlayer(unsigned requestId,unsigned replyId,DB_id playerId,int valid,int active)354 ServerDBThread::AsyncBlockPlayer(unsigned requestId, unsigned replyId, DB_id playerId, int valid, int active)
355 {
356 list<string> params;
357 ostringstream paramStream;
358 paramStream << valid;
359 params.push_back(paramStream.str());
360 paramStream.str("");
361 paramStream << active;
362 params.push_back(paramStream.str());
363 paramStream.str("");
364 paramStream << playerId;
365 params.push_back(paramStream.str());
366 boost::shared_ptr<AsyncDBQuery> asyncQuery(
367 new AsyncDBBlockPlayer(
368 requestId,
369 replyId,
370 QUERY_BLOCK_PLAYER_PREPARE,
371 params));
372
373 {
374 boost::mutex::scoped_lock lock(m_asyncQueueMutex);
375 m_asyncQueue.push(asyncQuery);
376 }
377 m_semaphore.post();
378 }
379
380 bool
IsConnected() const381 ServerDBThread::IsConnected() const
382 {
383 boost::mutex::scoped_lock lock(m_isConnectedMutex);
384 return m_isConnected;
385 }
386
387 void
Main()388 ServerDBThread::Main()
389 {
390 while (!ShouldTerminate() && !HasPermanentError()) {
391 if (HasDBConnection()) {
392 SetConnected(true);
393 m_semaphore.wait();
394 HandleNextQuery();
395 } else {
396 SetConnected(false);
397 EstablishDBConnection();
398 }
399 }
400 m_connData->conn.disconnect();
401 }
402
403 bool
HasPermanentError() const404 ServerDBThread::HasPermanentError() const
405 {
406 return m_permanentError;
407 }
408
409 bool
HasDBConnection() const410 ServerDBThread::HasDBConnection() const
411 {
412 return m_connData->conn.connected();
413 }
414
415 void
EstablishDBConnection()416 ServerDBThread::EstablishDBConnection()
417 {
418 m_connData->conn.set_option(new mysqlpp::SetCharsetNameOption("utf8"));
419 if (!m_connData->conn.connect(
420 m_connData->database.c_str(), m_connData->host.c_str(), m_connData->user.c_str(), m_connData->pwd.c_str())) {
421 m_ioService->post(boost::bind(&ServerDBCallback::ConnectFailed, &m_callback, m_connData->conn.error()));
422 if (!m_previouslyConnected)
423 m_permanentError = true;
424 else
425 Msleep(250);
426 } else {
427 mysqlpp::Query prepareNick = m_connData->conn.query();
428 /*
429 prepareNick
430 << "PREPARE " QUERY_NICK_PREPARE " FROM " << mysqlpp::quote
431 << "SELECT " DB_TABLE_PLAYER_COL_ID ", AES_DECRYPT(" DB_TABLE_PLAYER_COL_PASSWORD ", ?), " DB_TABLE_PLAYER_COL_VALID ", TRIM(" DB_TABLE_PLAYER_COL_COUNTRY "), " DB_TABLE_PLAYER_COL_LASTLOGIN ", " DB_TABLE_PLAYER_COL_ACTIVE " FROM " DB_TABLE_PLAYER " WHERE BINARY " DB_TABLE_PLAYER_COL_USERNAME " = ?";
432 */
433 prepareNick
434 << "PREPARE " QUERY_NICK_PREPARE " FROM " << mysqlpp::quote
435 << "SELECT " DB_TABLE_PLAYER_COL_ID ", AES_DECRYPT(" DB_TABLE_PLAYER_COL_PASSWORD ", ?), " DB_TABLE_PLAYER_COL_VALID ", TRIM(" DB_TABLE_PLAYER_COL_COUNTRY "), " DB_TABLE_PLAYER_COL_LASTLOGIN ", " DB_TABLE_PLAYER_COL_ACTIVE " FROM " DB_TABLE_PLAYER " WHERE " DB_TABLE_PLAYER_COL_USERNAME " = ?";
436
437 mysqlpp::Query prepareAvatarBlacklist = m_connData->conn.query();
438 prepareAvatarBlacklist
439 << "PREPARE " QUERY_AVATAR_BLACKLIST_PREPARE " FROM " << mysqlpp::quote
440 << "SELECT " DB_TABLE_AVATAR_BLACKLIST_COL_ID " FROM " DB_TABLE_AVATAR_BLACKLIST " WHERE BINARY " DB_TABLE_AVATAR_BLACKLIST_COL_AVATAR_HASH " = ?";
441
442 mysqlpp::Query prepareLogin = m_connData->conn.query();
443 prepareLogin
444 << "PREPARE " QUERY_LOGIN_PREPARE " FROM " << mysqlpp::quote
445 << "UPDATE " DB_TABLE_PLAYER " SET " DB_TABLE_PLAYER_COL_LASTLOGIN " = ?, " DB_TABLE_PLAYER_COL_AVATARHASH " = ?, " DB_TABLE_PLAYER_COL_AVATARTYPE " = ? WHERE " DB_TABLE_PLAYER_COL_ID " = ?";
446 mysqlpp::Query prepareCreateGame = m_connData->conn.query();
447 prepareCreateGame
448 << "PREPARE " QUERY_CREATE_GAME_PREPARE " FROM " << mysqlpp::quote
449 << "INSERT INTO " DB_TABLE_GAME " (" DB_TABLE_GAME_COL_NAME ", " DB_TABLE_GAME_COL_STARTTIME ") VALUES (?, ?)";
450 mysqlpp::Query prepareEndGame = m_connData->conn.query();
451 prepareEndGame
452 << "PREPARE " QUERY_END_GAME_PREPARE " FROM " << mysqlpp::quote
453 << "UPDATE " DB_TABLE_GAME " SET "DB_TABLE_GAME_COL_ENDTIME " = ? WHERE " DB_TABLE_GAME_COL_ID " = ?";
454 mysqlpp::Query prepareRelation = m_connData->conn.query();
455 prepareRelation
456 << "PREPARE " QUERY_GAME_PLAYER_PREPARE " FROM " << mysqlpp::quote
457 << "INSERT INTO " DB_TABLE_GAMEPLAYER " (" DB_TABLE_GAMEPLAYER_COL_GAMEID ", " DB_TABLE_GAMEPLAYER_COL_PLAYERID ", " DB_TABLE_GAMEPLAYER_COL_PLACE ") VALUES (?, ?, ?)";
458 mysqlpp::Query prepareScore = m_connData->conn.query();
459 prepareScore
460 << "PREPARE " QUERY_UPDATE_SCORE_PREPARE " FROM " << mysqlpp::quote
461 << "CALL updatePointsForGame(?)";
462
463 mysqlpp::Query prepareReportAvatar = m_connData->conn.query();
464 prepareReportAvatar
465 << "PREPARE " QUERY_REPORT_AVATAR_PREPARE " FROM " << mysqlpp::quote
466 << "INSERT INTO " DB_TABLE_REP_AVATAR " (" DB_TABLE_REP_AVATAR_COL_PLAYERID ", " DB_TABLE_REP_AVATAR_COL_AVATARHASH ", " DB_TABLE_REP_AVATAR_COL_AVATARTYPE ", " DB_TABLE_REP_AVATAR_COL_BY_PLAYERID ", " DB_TABLE_REP_AVATAR_COL_TIMESTAMP ") VALUES (?, ?, ?, ?, ?)";
467
468 mysqlpp::Query prepareReportGame = m_connData->conn.query();
469 prepareReportGame
470 << "PREPARE " QUERY_REPORT_GAME_PREPARE " FROM " << mysqlpp::quote
471 << "INSERT INTO " DB_TABLE_REP_GAME " (" DB_TABLE_REP_GAME_COL_CREATOR ", " DB_TABLE_REP_GAME_COL_GAMENAME ", " DB_TABLE_REP_GAME_COL_BY_PLAYERID ", " DB_TABLE_REP_GAME_COL_TIMESTAMP ", " DB_TABLE_REP_GAME_COL_GAMEID ") VALUES (?, ?, ?, ?, ?)";
472
473 mysqlpp::Query prepareAdminPlayer = m_connData->conn.query();
474 prepareAdminPlayer
475 << "PREPARE " QUERY_ADMIN_PLAYER_PREPARE " FROM " << mysqlpp::quote
476 << "SELECT " DB_TABLE_ADMIN_PLAYER_COL_PLAYERID " FROM " DB_TABLE_ADMIN_PLAYER;
477
478 mysqlpp::Query prepareBlockPlayer = m_connData->conn.query();
479 prepareBlockPlayer
480 << "PREPARE " QUERY_BLOCK_PLAYER_PREPARE " FROM " << mysqlpp::quote
481 << "UPDATE " DB_TABLE_PLAYER " SET " DB_TABLE_PLAYER_COL_VALID " = ?, " DB_TABLE_PLAYER_COL_ACTIVE " = ? WHERE " DB_TABLE_PLAYER_COL_ID " = ?";
482 if (!prepareNick.exec() || !prepareAvatarBlacklist.exec() || !prepareLogin.exec() || !prepareCreateGame.exec()
483 || !prepareEndGame.exec() || !prepareRelation.exec() || !prepareScore.exec() || !prepareReportAvatar.exec()
484 || !prepareReportGame.exec() || !prepareAdminPlayer.exec() || !prepareBlockPlayer.exec()) {
485 string tmpError = string(prepareNick.error()) + prepareAvatarBlacklist.error() + prepareLogin.error() + prepareCreateGame.error() +
486 prepareEndGame.error() + prepareRelation.error() + prepareScore.error() + prepareReportAvatar.error() +
487 prepareReportGame.error() + prepareAdminPlayer.error() + prepareBlockPlayer.error();
488 m_connData->conn.disconnect();
489 m_ioService->post(boost::bind(&ServerDBCallback::ConnectFailed, &m_callback, tmpError));
490 m_permanentError = true;
491 } else {
492 m_ioService->post(boost::bind(&ServerDBCallback::ConnectSuccess, &m_callback));
493 m_previouslyConnected = true;
494 }
495 }
496 }
497
498 void
HandleNextQuery()499 ServerDBThread::HandleNextQuery()
500 {
501 boost::shared_ptr<AsyncDBQuery> nextQuery;
502 {
503 boost::mutex::scoped_lock lock(m_asyncQueueMutex);
504 if (!m_asyncQueue.empty()) {
505 nextQuery = m_asyncQueue.front();
506 m_asyncQueue.pop();
507 }
508 }
509 if (nextQuery) {
510 do {
511 nextQuery->Init(m_dbIdManager);
512 mysqlpp::Query executeQuery = m_connData->conn.query();
513 executeQuery << "EXECUTE " << nextQuery->GetPreparedName();
514
515 list<string> paramList;
516 nextQuery->GetParams(paramList);
517 if (!paramList.empty()) {
518 executeQuery << " using ";
519 mysqlpp::Query paramQuery = m_connData->conn.query();
520 paramQuery << "SET ";
521 unsigned counter = 1;
522 list<string>::iterator i = paramList.begin();
523 list<string>::iterator end = paramList.end();
524 while (i != end) {
525 if (counter > 1) {
526 paramQuery << ", ";
527 executeQuery << ", ";
528 }
529 paramQuery << "@param" << counter << " = ";
530 if (*i == "NULL") {
531 paramQuery << "NULL";
532 } else {
533 paramQuery << "_utf8" << mysqlpp::quote << *i;
534 }
535 executeQuery << "@param" << counter;
536 ++counter;
537 ++i;
538 }
539 if (!paramQuery.exec()) {
540 string tmpError = paramQuery.error();
541 m_connData->conn.disconnect();
542 m_ioService->post(boost::bind(&ServerDBCallback::QueryError, &m_callback, tmpError));
543 break;
544 }
545 }
546 if (nextQuery->RequiresResultSet()) {
547 mysqlpp::StoreQueryResult res = executeQuery.store();
548 if (res)
549 nextQuery->HandleResult(executeQuery, m_dbIdManager, res, *m_ioService, m_callback);
550 else
551 nextQuery->HandleError(*m_ioService, m_callback);
552 } else {
553 if (executeQuery.exec())
554 nextQuery->HandleNoResult(executeQuery, m_dbIdManager, *m_ioService, m_callback);
555 else
556 nextQuery->HandleError(*m_ioService, m_callback);
557 }
558 } while (nextQuery->Next()); // Consider composite queries.
559 }
560 }
561
562 void
SetConnected(bool isConnected)563 ServerDBThread::SetConnected(bool isConnected)
564 {
565 boost::mutex::scoped_lock lock(m_isConnectedMutex);
566 m_isConnected = isConnected;
567 }
568
569