The Battle for Wesnoth  1.17.0+dev
dbconn.cpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2020 - 2021
3  Part of the Battle for Wesnoth Project https://www.wesnoth.org/
4 
5  This program is free software; you can redistribute it and/or modify
6  it under the terms of the GNU General Public License as published by
7  the Free Software Foundation; either version 2 of the License, or
8  (at your option) any later version.
9  This program is distributed in the hope that it will be useful,
10  but WITHOUT ANY WARRANTY.
11 
12  See the COPYING file for more details.
13 */
14 
15 #ifdef HAVE_MYSQLPP
16 
17 #include "server/common/dbconn.hpp"
21 
22 #include "log.hpp"
24 
25 static lg::log_domain log_sql_handler("sql_executor");
26 #define ERR_SQL LOG_STREAM(err, log_sql_handler)
27 #define WRN_SQL LOG_STREAM(warn, log_sql_handler)
28 #define LOG_SQL LOG_STREAM(info, log_sql_handler)
29 #define DBG_SQL LOG_STREAM(debug, log_sql_handler)
30 
31 dbconn::dbconn(const config& c)
32  : db_users_table_(c["db_users_table"].str())
33  , db_banlist_table_(c["db_banlist_table"].str())
34  , db_extra_table_(c["db_extra_table"].str())
35  , db_game_info_table_(c["db_game_info_table"].str())
36  , db_game_player_info_table_(c["db_game_player_info_table"].str())
37  , db_game_content_info_table_(c["db_game_content_info_table"].str())
38  , db_user_group_table_(c["db_user_group_table"].str())
39  , db_tournament_query_(c["db_tournament_query"].str())
40  , db_topics_table_(c["db_topics_table"].str())
41  , db_addon_info_table_(c["db_addon_info_table"].str())
42  , db_connection_history_table_(c["db_connection_history_table"].str())
43 {
44  try
45  {
46  account_ = mariadb::account::create(c["db_host"].str(), c["db_user"].str(), c["db_password"].str());
47  account_->set_connect_option(mysql_option::MYSQL_SET_CHARSET_NAME, std::string("utf8mb4"));
48  account_->set_schema(c["db_name"].str());
49  // initialize the connection used to run synchronous queries.
50  connection_ = create_connection();
51  }
52  catch(const mariadb::exception::base& e)
53  {
54  log_sql_exception("Failed to connect to the database!", e);
55  }
56 }
57 
58 void dbconn::log_sql_exception(const std::string& text, const mariadb::exception::base& e)
59 {
60  ERR_SQL << text << '\n'
61  << "what: " << e.what() << '\n'
62  << "error id: " << e.error_id() << std::endl;
63 }
64 
65 mariadb::connection_ref dbconn::create_connection()
66 {
67  return mariadb::connection::create(account_);
68 }
69 
70 //
71 // queries
72 //
73 int dbconn::async_test_query(int limit)
74 {
75  std::string sql = "with recursive TEST(T) as "
76  "( "
77  "select 1 "
78  "union all "
79  "select T+1 from TEST where T < ? "
80  ") "
81  "select count(*) from TEST";
82  int t = get_single_long(create_connection(), sql, limit);
83  return t;
84 }
85 
86 std::string dbconn::get_uuid()
87 {
88  try
89  {
90  return get_single_string(connection_, "SELECT UUID()");
91  }
92  catch(const mariadb::exception::base& e)
93  {
94  log_sql_exception("Could not retrieve a UUID!", e);
95  return "";
96  }
97 }
98 
99 std::string dbconn::get_tournaments()
100 {
101  if(db_tournament_query_ == "")
102  {
103  return "";
104  }
105 
106  try
107  {
108  tournaments t;
109  get_complex_results(connection_, t, db_tournament_query_);
110  return t.str();
111  }
112  catch(const mariadb::exception::base& e)
113  {
114  log_sql_exception("Could not retrieve the tournaments!", e);
115  return "";
116  }
117 }
118 
119 std::unique_ptr<simple_wml::document> dbconn::get_game_history(int player_id, int offset)
120 {
121  try
122  {
123  std::string game_history_query = "select "
124 " game.GAME_NAME, "
125 " game.RELOAD, "
126 " game.START_TIME, "
127 " GROUP_CONCAT(CONCAT(player.USER_NAME, ':', player.FACTION)) as PLAYERS, "
128 " IFNULL(scenario.NAME, '') as SCENARIO_NAME, "
129 " IFNULL(scenario.ID, '') as SCENARIO_ID, "
130 " IFNULL(era.NAME, '') as ERA_NAME, "
131 " IFNULL(era.ID, '') as ERA_ID, "
132 " IFNULL(GROUP_CONCAT(distinct mods.NAME, '') as MODIFICATION_NAMES, "
133 " IFNULL(GROUP_CONCAT(distinct mods.ID), '') as MODIFICATION_IDS, "
134 " case "
135 " when game.PUBLIC = 1 "
136 " then concat('https://replays.wesnoth.org/', substring(game.INSTANCE_VERSION, 1, 4), '/', year(game.END_TIME), '/', lpad(month(game.END_TIME), 2, '0'), '/', lpad(day(game.END_TIME), 2, '0'), '/', game.REPLAY_NAME) "
137 " else '' "
138 " end as REPLAY_URL "
139 "from "+db_game_info_table_+" game "
140 "inner join "+db_game_player_info_table_+" player "
141 " on exists "
142 " ( "
143 " select 1 "
144 " from "+db_game_player_info_table_+" player1 "
145 " where game.INSTANCE_UUID = player1.INSTANCE_UUID "
146 " and game.GAME_ID = player1.GAME_ID "
147 " and player1.USER_ID = ? "
148 " ) "
149 " and game.INSTANCE_UUID = player.INSTANCE_UUID "
150 " and game.GAME_ID = player.GAME_ID "
151 " and player.USER_ID != -1 "
152 " and game.END_TIME is not NULL "
153 "inner join "+db_game_content_info_table_+" scenario "
154 " on scenario.TYPE = 'scenario' "
155 " and scenario.INSTANCE_UUID = game.INSTANCE_UUID "
156 " and scenario.GAME_ID = game.GAME_ID "
157 "inner join "+db_game_content_info_table_+" era "
158 " on era.TYPE = 'era' "
159 " and era.INSTANCE_UUID = game.INSTANCE_UUID "
160 " and era.GAME_ID = game.GAME_ID "
161 "left join "+db_game_content_info_table_+" mods "
162 " on mods.TYPE = 'modification' "
163 " and mods.INSTANCE_UUID = game.INSTANCE_UUID "
164 " and mods.GAME_ID = game.GAME_ID "
165 "group by game.INSTANCE_UUID, game.GAME_ID "
166 "order by game.START_TIME desc "
167 "limit 11 offset ? ";
168 
169  game_history gh;
170  get_complex_results(create_connection(), gh, game_history_query, player_id, offset);
171  return gh.to_doc();
172  }
173  catch(const mariadb::exception::base& e)
174  {
175  log_sql_exception("Could not retrieve the game history for forum ID `"+std::to_string(player_id)+"`!", e);
176  auto doc = std::make_unique<simple_wml::document>();
177  doc->set_attr("error", "Error retrieving game history.");
178  return doc;
179  }
180 }
181 
182 bool dbconn::user_exists(const std::string& name)
183 {
184  try
185  {
186  return exists(connection_, "SELECT 1 FROM `"+db_users_table_+"` WHERE UPPER(username)=UPPER(?)", name);
187  }
188  catch(const mariadb::exception::base& e)
189  {
190  log_sql_exception("Unable to check if user row for '"+name+"' exists!", e);
191  return false;
192  }
193 }
194 
195 long dbconn::get_forum_id(const std::string& name)
196 {
197  try
198  {
199  return get_single_long(connection_, "SELECT IFNULL((SELECT user_id FROM `"+db_users_table_+"` WHERE UPPER(username)=UPPER(?)), 0)", name);
200  }
201  catch(const mariadb::exception::base& e)
202  {
203  log_sql_exception("Unable to get user_id for '"+name+"'!", e);
204  return 0;
205  }
206 }
207 
208 bool dbconn::extra_row_exists(const std::string& name)
209 {
210  try
211  {
212  return exists(connection_, "SELECT 1 FROM `"+db_extra_table_+"` WHERE UPPER(username)=UPPER(?)", name);
213  }
214  catch(const mariadb::exception::base& e)
215  {
216  log_sql_exception("Unable to check if extra row for '"+name+"' exists!", e);
217  return false;
218  }
219 }
220 
221 bool dbconn::is_user_in_group(const std::string& name, int group_id)
222 {
223  try
224  {
225  return exists(connection_, "SELECT 1 FROM `"+db_users_table_+"` u, `"+db_user_group_table_+"` ug WHERE UPPER(u.username)=UPPER(?) AND u.USER_ID = ug.USER_ID AND ug.GROUP_ID = ?",
226  name, group_id);
227  }
228  catch(const mariadb::exception::base& e)
229  {
230  log_sql_exception("Unable to check if the user '"+name+"' is in group '"+std::to_string(group_id)+"'!", e);
231  return false;
232  }
233 }
234 
235 ban_check dbconn::get_ban_info(const std::string& name, const std::string& ip)
236 {
237  try
238  {
239  // selected ban_type value must be part of user_handler::BAN_TYPE
240  ban_check b;
241  get_complex_results(connection_, b, "select ban_userid, ban_email, case when ban_ip != '' then 1 when ban_userid != 0 then 2 when ban_email != '' then 3 end as ban_type, ban_end from `"+db_banlist_table_+"` where (ban_ip = ? or ban_userid = (select user_id from `"+db_users_table_+"` where UPPER(username) = UPPER(?)) or UPPER(ban_email) = (select UPPER(user_email) from `"+db_users_table_+"` where UPPER(username) = UPPER(?))) AND ban_exclude = 0 AND (ban_end = 0 OR ban_end >= ?)",
242  ip, name, name, std::time(nullptr));
243  return b;
244  }
245  catch(const mariadb::exception::base& e)
246  {
247  log_sql_exception("Failed to check ban info for user '"+name+"' connecting from ip '"+ip+"'!", e);
248  return ban_check();
249  }
250 }
251 
252 std::string dbconn::get_user_string(const std::string& table, const std::string& column, const std::string& name)
253 {
254  try
255  {
256  return get_single_string(connection_, "SELECT `"+column+"` from `"+table+"` WHERE UPPER(username)=UPPER(?)", name);
257  }
258  catch(const mariadb::exception::base& e)
259  {
260  log_sql_exception("Unable to query column `"+column+"` from table `"+table+"` for user `"+name+"`", e);
261  return "";
262  }
263 }
264 int dbconn::get_user_int(const std::string& table, const std::string& column, const std::string& name)
265 {
266  try
267  {
268  return static_cast<int>(get_single_long(connection_, "SELECT `"+column+"` from `"+table+"` WHERE UPPER(username)=UPPER(?)", name));
269  }
270  catch(const mariadb::exception::base& e)
271  {
272  log_sql_exception("Unable to query column `"+column+"` from table `"+table+"` for user `"+name+"`", e);
273  return 0;
274  }
275 }
276 void dbconn::write_user_int(const std::string& column, const std::string& name, int value)
277 {
278  try
279  {
280  if(!extra_row_exists(name))
281  {
282  modify(connection_, "INSERT INTO `"+db_extra_table_+"` VALUES(?,?,'0')", name, value);
283  }
284  modify(connection_, "UPDATE `"+db_extra_table_+"` SET "+column+"=? WHERE UPPER(username)=UPPER(?)", value, name);
285  }
286  catch(const mariadb::exception::base& e)
287  {
288  log_sql_exception("Unable to write `"+std::to_string(value)+"` to column `"+column+"` on table `"+db_extra_table_+"` for user `"+name+"`", e);
289  }
290 }
291 
292 void dbconn::insert_game_info(const std::string& uuid, int game_id, const std::string& version, const std::string& name, int reload, int observers, int is_public, int has_password)
293 {
294  try
295  {
296  modify(connection_, "INSERT INTO `"+db_game_info_table_+"`(INSTANCE_UUID, GAME_ID, INSTANCE_VERSION, GAME_NAME, RELOAD, OBSERVERS, PUBLIC, PASSWORD) VALUES(?, ?, ?, ?, ?, ?, ?, ?)",
297  uuid, game_id, version, name, reload, observers, is_public, has_password);
298  }
299  catch(const mariadb::exception::base& e)
300  {
301  log_sql_exception("Failed to insert game info row for UUID `"+uuid+"` and game ID `"+std::to_string(game_id)+"`", e);
302  }
303 }
304 void dbconn::update_game_end(const std::string& uuid, int game_id, const std::string& replay_location)
305 {
306  try
307  {
308  modify(connection_, "UPDATE `"+db_game_info_table_+"` SET END_TIME = CURRENT_TIMESTAMP, REPLAY_NAME = ? WHERE INSTANCE_UUID = ? AND GAME_ID = ?",
309  replay_location, uuid, game_id);
310  }
311  catch(const mariadb::exception::base& e)
312  {
313  log_sql_exception("Failed to update the game end for game info row for UUID `"+uuid+"` and game ID `"+std::to_string(game_id)+"`", e);
314  }
315 }
316 void dbconn::insert_game_player_info(const std::string& uuid, int game_id, const std::string& username, int side_number, int is_host, const std::string& faction, const std::string& version, const std::string& source, const std::string& current_user)
317 {
318  try
319  {
320  modify(connection_, "INSERT INTO `"+db_game_player_info_table_+"`(INSTANCE_UUID, GAME_ID, USER_ID, SIDE_NUMBER, IS_HOST, FACTION, CLIENT_VERSION, CLIENT_SOURCE, USER_NAME) VALUES(?, ?, IFNULL((SELECT user_id FROM `"+db_users_table_+"` WHERE username = ?), -1), ?, ?, ?, ?, ?, ?)",
321  uuid, game_id, username, side_number, is_host, faction, version, source, current_user);
322  }
323  catch(const mariadb::exception::base& e)
324  {
325  log_sql_exception("Failed to insert game player info row for UUID `"+uuid+"` and game ID `"+std::to_string(game_id)+"`", e);
326  }
327 }
328 unsigned long long dbconn::insert_game_content_info(const std::string& uuid, int game_id, const std::string& type, const std::string& name, const std::string& id, const std::string& source, const std::string& version)
329 {
330  try
331  {
332  return modify(connection_, "INSERT INTO `"+db_game_content_info_table_+"`(INSTANCE_UUID, GAME_ID, TYPE, NAME, ID, SOURCE, VERSION) VALUES(?, ?, ?, ?, ?, ?, ?)",
333  uuid, game_id, type, name, id, source, version);
334  }
335  catch(const mariadb::exception::base& e)
336  {
337  log_sql_exception("Failed to insert game content info row for UUID `"+uuid+"` and game ID `"+std::to_string(game_id)+"`", e);
338  return 0;
339  }
340 }
341 void dbconn::set_oos_flag(const std::string& uuid, int game_id)
342 {
343  try
344  {
345  modify(connection_, "UPDATE `"+db_game_info_table_+"` SET OOS = 1 WHERE INSTANCE_UUID = ? AND GAME_ID = ?",
346  uuid, game_id);
347  }
348  catch(const mariadb::exception::base& e)
349  {
350  log_sql_exception("Failed to set the OOS flag for UUID `"+uuid+"` and game ID `"+std::to_string(game_id)+"`", e);
351  }
352 }
353 
354 bool dbconn::topic_id_exists(int topic_id) {
355  try
356  {
357  return exists(connection_, "SELECT 1 FROM `"+db_topics_table_+"` WHERE TOPIC_ID = ?",
358  topic_id);
359  }
360  catch(const mariadb::exception::base& e)
361  {
362  log_sql_exception("Unable to check whether `"+std::to_string(topic_id)+"` exists.", e);
363  return true;
364  }
365 }
366 
367 void dbconn::insert_addon_info(const std::string& instance_version, const std::string& id, const std::string& name, const std::string& type, const std::string& version, bool forum_auth, int topic_id)
368 {
369  try
370  {
371  modify(connection_, "INSERT INTO `"+db_addon_info_table_+"`(INSTANCE_VERSION, ADDON_ID, ADDON_NAME, TYPE, VERSION, FORUM_AUTH, FEEDBACK_TOPIC) VALUES(?, ?, ?, ?, ?, ?, ?)",
372  instance_version, id, name, type, version, forum_auth, topic_id);
373  }
374  catch(const mariadb::exception::base& e)
375  {
376  log_sql_exception("Unable to insert add-on info for add-on `"+id+"` for instance `"+instance_version+"`.", e);
377  }
378 }
379 
380 unsigned long long dbconn::insert_login(const std::string& username, const std::string& ip, const std::string& version)
381 {
382  try
383  {
384  return modify_get_id(connection_, "INSERT INTO `"+db_connection_history_table_+"`(USER_NAME, IP, VERSION) values(lower(?), ?, ?)",
385  username, ip, version);
386  }
387  catch(const mariadb::exception::base& e)
388  {
389  log_sql_exception("Unable to insert login row user `"+username+"` and ip `"+ip+"`.", e);
390  return 0;
391  }
392 }
393 
394 void dbconn::update_logout(unsigned long long login_id)
395 {
396  try
397  {
398  modify(connection_, "UPDATE `"+db_connection_history_table_+"` SET LOGOUT_TIME = CURRENT_TIMESTAMP WHERE LOGIN_ID = ?",
399  login_id);
400  }
401  catch(const mariadb::exception::base& e)
402  {
403  log_sql_exception("Unable to update login row `"+std::to_string(login_id)+"`.", e);
404  }
405 }
406 
407 void dbconn::get_users_for_ip(const std::string& ip, std::ostringstream* out)
408 {
409  try
410  {
411  mariadb::result_set_ref rslt = select(connection_, "SELECT USER_NAME, IP, date_format(LOGIN_TIME, '%Y/%m/%d %h:%i:%s'), coalesce(date_format(LOGOUT_TIME, '%Y/%m/%d %h:%i:%s'), '(not set)') FROM `"+db_connection_history_table_+"` WHERE IP LIKE ? order by LOGIN_TIME",
412  ip);
413 
414  *out << "\nCount of results for ip: " << rslt->row_count();
415 
416  while(rslt->next())
417  {
418  *out << "\nFound user " << rslt->get_string(0) << " with ip " << rslt->get_string(1)
419  << ", logged in at " << rslt->get_string(2) << " and logged out at " << rslt->get_string(3);
420  }
421  }
422  catch(const mariadb::exception::base& e)
423  {
424  log_sql_exception("Unable to select rows for ip `"+ip+"`.", e);
425  }
426 }
427 
428 void dbconn::get_ips_for_user(const std::string& username, std::ostringstream* out)
429 {
430  try
431  {
432  mariadb::result_set_ref rslt = select(connection_, "SELECT USER_NAME, IP, date_format(LOGIN_TIME, '%Y/%m/%d %h:%i:%s'), coalesce(date_format(LOGOUT_TIME, '%Y/%m/%d %h:%i:%s'), '(not set)') FROM `"+db_connection_history_table_+"` WHERE USER_NAME LIKE ? order by LOGIN_TIME",
433  utf8::lowercase(username));
434 
435  *out << "\nCount of results for user: " << rslt->row_count();
436 
437  while(rslt->next())
438  {
439  *out << "\nFound user " << rslt->get_string(0) << " with ip " << rslt->get_string(1)
440  << ", logged in at " << rslt->get_string(2) << " and logged out at " << rslt->get_string(3);
441  }
442  }
443  catch(const mariadb::exception::base& e)
444  {
445  log_sql_exception("Unable to select rows for player `"+username+"`.", e);
446  }
447 }
448 
449 //
450 // handle complex query results
451 //
452 template<typename... Args>
453 void dbconn::get_complex_results(mariadb::connection_ref connection, rs_base& base, const std::string& sql, Args&&... args)
454 {
455  mariadb::result_set_ref rslt = select(connection, sql, args...);
456  base.read(rslt);
457 }
458 //
459 // handle single values
460 //
461 template<typename... Args>
462 std::string dbconn::get_single_string(mariadb::connection_ref connection, const std::string& sql, Args&&... args)
463 {
464  mariadb::result_set_ref rslt = select(connection, sql, args...);
465  if(rslt->next())
466  {
467  return rslt->get_string(0);
468  }
469  else
470  {
471  throw mariadb::exception::base("No string value found in the database!");
472  }
473 }
474 template<typename... Args>
475 long dbconn::get_single_long(mariadb::connection_ref connection, const std::string& sql, Args&&... args)
476 {
477  mariadb::result_set_ref rslt = select(connection, sql, args...);
478  if(rslt->next())
479  {
480  // mariadbpp checks for strict integral equivalence, but we don't care
481  // so check the type beforehand, call the associated getter, and let it silently get upcast to a long if needed
482  // subselects also apparently return a decimal
483  switch(rslt->column_type(0))
484  {
485  case mariadb::value::type::decimal:
486  return static_cast<long>(rslt->get_decimal(0).float32());
487  case mariadb::value::type::unsigned8:
488  case mariadb::value::type::signed8:
489  return rslt->get_signed8(0);
490  case mariadb::value::type::unsigned16:
491  case mariadb::value::type::signed16:
492  return rslt->get_signed16(0);
493  case mariadb::value::type::unsigned32:
494  case mariadb::value::type::signed32:
495  return rslt->get_signed32(0);
496  case mariadb::value::type::unsigned64:
497  case mariadb::value::type::signed64:
498  return rslt->get_signed64(0);
499  default:
500  throw mariadb::exception::base("Value retrieved was not a long!");
501  }
502  }
503  else
504  {
505  throw mariadb::exception::base("No long value found in the database!");
506  }
507 }
508 template<typename... Args>
509 bool dbconn::exists(mariadb::connection_ref connection, const std::string& sql, Args&&... args)
510 {
511  mariadb::result_set_ref rslt = select(connection, sql, args...);
512  return rslt->next();
513 }
514 
515 //
516 // select or modify values
517 //
518 template<typename... Args>
519 mariadb::result_set_ref dbconn::select(mariadb::connection_ref connection, const std::string& sql, Args&&... args)
520 {
521  try
522  {
523  mariadb::statement_ref stmt = query(connection, sql, args...);
524  mariadb::result_set_ref rslt = mariadb::result_set_ref(stmt->query());
525  return rslt;
526  }
527  catch(const mariadb::exception::base& e)
528  {
529  ERR_SQL << "SQL query failed for query: `"+sql+"`" << std::endl;
530  throw e;
531  }
532 }
533 template<typename... Args>
534 unsigned long long dbconn::modify(mariadb::connection_ref connection, const std::string& sql, Args&&... args)
535 {
536  try
537  {
538  mariadb::statement_ref stmt = query(connection, sql, args...);
539  unsigned long long count = stmt->execute();
540  return count;
541  }
542  catch(const mariadb::exception::base& e)
543  {
544  ERR_SQL << "SQL query failed for query: `"+sql+"`" << std::endl;
545  throw e;
546  }
547 }
548 template<typename... Args>
549 unsigned long long dbconn::modify_get_id(mariadb::connection_ref connection, const std::string& sql, Args&&... args)
550 {
551  try
552  {
553  mariadb::statement_ref stmt = query(connection, sql, args...);
554  unsigned long long count = stmt->insert();
555  return count;
556  }
557  catch(const mariadb::exception::base& e)
558  {
559  ERR_SQL << "SQL query failed for query: `"+sql+"`" << std::endl;
560  throw e;
561  }
562 }
563 
564 
565 
566 
567 template<typename... Args>
568 mariadb::statement_ref dbconn::query(mariadb::connection_ref connection, const std::string& sql, Args&&... args)
569 {
570  mariadb::statement_ref stmt = connection->create_statement(sql);
571  prepare(stmt, 0, args...);
572  return stmt;
573 }
574 
575 template<typename Arg, typename... Args>
576 void dbconn::prepare(mariadb::statement_ref stmt, int i, Arg arg, Args&&... args)
577 {
578  i = prepare(stmt, i, arg);
579  prepare(stmt, i, args...);
580 }
581 
582 template<>
583 int dbconn::prepare(mariadb::statement_ref stmt, int i, bool arg)
584 {
585  stmt->set_boolean(i++, arg);
586  return i;
587 }
588 template<>
589 int dbconn::prepare(mariadb::statement_ref stmt, int i, int arg)
590 {
591  stmt->set_signed32(i++, arg);
592  return i;
593 }
594 template<>
595 int dbconn::prepare(mariadb::statement_ref stmt, int i, long arg)
596 {
597  stmt->set_signed64(i++, arg);
598  return i;
599 }
600 template<>
601 int dbconn::prepare(mariadb::statement_ref stmt, int i, unsigned long long arg)
602 {
603  stmt->set_unsigned64(i++, arg);
604  return i;
605 }
606 template<>
607 int dbconn::prepare(mariadb::statement_ref stmt, int i, const char* arg)
608 {
609  stmt->set_string(i++, arg);
610  return i;
611 }
612 template<>
613 int dbconn::prepare(mariadb::statement_ref stmt, int i, std::string arg)
614 {
615  stmt->set_string(i++, arg);
616  return i;
617 }
618 
619 void dbconn::prepare(mariadb::statement_ref, int){}
620 
621 #endif //HAVE_MYSQLPP
void prepare(mariadb::statement_ref stmt, int i, Arg arg, Args &&... args)
The next parameter to be added is split off from the parameter pack.
void insert_addon_info(const std::string &instance_version, const std::string &id, const std::string &name, const std::string &type, const std::string &version, bool forum_auth, int topic_id)
int async_test_query(int limit)
std::string get_user_string(const std::string &table, const std::string &column, const std::string &name)
void update_logout(unsigned long long login_id)
bool topic_id_exists(int topic_id)
std::string get_tournaments()
unsigned long long modify_get_id(mariadb::connection_ref connection, const std::string &sql, Args &&... args)
Executes non-select statements (ie: insert, update, delete), but primarily intended for inserts that ...
void insert_game_info(const std::string &uuid, int game_id, const std::string &version, const std::string &name, int reload, int observers, int is_public, int has_password)
void get_complex_results(mariadb::connection_ref connection, rs_base &base, const std::string &sql, Args &&... args)
Queries can return data with various types that can&#39;t be easily fit into a pre-determined structure...
int get_user_int(const std::string &table, const std::string &column, const std::string &name)
unsigned long long insert_game_content_info(const std::string &uuid, int game_id, const std::string &type, const std::string &name, const std::string &id, const std::string &source, const std::string &version)
std::string get_single_string(mariadb::connection_ref connection, const std::string &sql, Args &&... args)
mariadb::connection_ref create_connection()
Creates a new connection object from the account.
dbconn(const config &c)
Initializes the synchronous query connection as well as the account object that has the connection se...
#define b
bool exists(const image::locator &i_locator)
Returns true if the given image actually exists, without loading it.
Definition: picture.cpp:1011
virtual void read(mariadb::result_set_ref rslt)=0
void write_user_int(const std::string &column, const std::string &name, int value)
The provided value is updated if a row exists or a new row inserted otherwise.
long get_single_long(mariadb::connection_ref connection, const std::string &sql, Args &&... args)
unsigned long long modify(mariadb::connection_ref connection, const std::string &sql, Args &&... args)
Executes non-select statements (ie: insert, update, delete).
bool is_user_in_group(const std::string &name, int group_id)
void get_users_for_ip(const std::string &ip, std::ostringstream *out)
std::string get_uuid()
std::size_t i
Definition: function.cpp:967
void set_oos_flag(const std::string &uuid, int game_id)
bool user_exists(const std::string &name)
void get_ips_for_user(const std::string &username, std::ostringstream *out)
std::string str()
std::unique_ptr< simple_wml::document > get_game_history(int player_id, int offset)
This is an asynchronous query that is executed on a separate connection to retrieve the game history ...
std::string lowercase(const std::string &s)
Returns a lowercased version of the string.
Definition: unicode.cpp:52
long get_forum_id(const std::string &name)
mariadb::statement_ref query(mariadb::connection_ref connection, const std::string &sql, Args &&... args)
Begins recursively unpacking of the parameter pack in order to be able to call the correct parameteri...
void log_sql_exception(const std::string &text, const mariadb::exception::base &e)
This is used to write out error text when an SQL-related exception occurs.
double t
Definition: astarsearch.cpp:65
void insert_game_player_info(const std::string &uuid, int game_id, const std::string &username, int side_number, int is_host, const std::string &faction, const std::string &version, const std::string &source, const std::string &current_user)
mariadb::result_set_ref select(mariadb::connection_ref connection, const std::string &sql, Args &&... args)
Executes a select statement.
#define e
int side_number
Definition: game_info.hpp:40
ban_check get_ban_info(const std::string &name, const std::string &ip)
A config object defines a single node in a WML file, with access to child nodes.
Definition: config.hpp:61
mock_char c
std::unique_ptr< simple_wml::document > to_doc()
unsigned long long insert_login(const std::string &username, const std::string &ip, const std::string &version)
void update_game_end(const std::string &uuid, int game_id, const std::string &replay_location)
bool extra_row_exists(const std::string &name)
bool exists(mariadb::connection_ref connection, const std::string &sql, Args &&... args)