25 #include <type_traits> 
   28 #define ERR_SQL LOG_STREAM(err, log_sql_handler) 
   29 #define WRN_SQL LOG_STREAM(warn, log_sql_handler) 
   30 #define LOG_SQL LOG_STREAM(info, log_sql_handler) 
   31 #define DBG_SQL LOG_STREAM(debug, log_sql_handler) 
   34     : db_users_table_(
c[
"db_users_table"].str())
 
   35     , db_banlist_table_(
c[
"db_banlist_table"].str())
 
   36     , db_extra_table_(
c[
"db_extra_table"].str())
 
   37     , db_game_info_table_(
c[
"db_game_info_table"].str())
 
   38     , db_game_player_info_table_(
c[
"db_game_player_info_table"].str())
 
   39     , db_game_content_info_table_(
c[
"db_game_content_info_table"].str())
 
   40     , db_user_group_table_(
c[
"db_user_group_table"].str())
 
   41     , db_tournament_query_(
c[
"db_tournament_query"].str())
 
   42     , db_topics_table_(
c[
"db_topics_table"].str())
 
   43     , db_addon_info_table_(
c[
"db_addon_info_table"].str())
 
   44     , db_connection_history_table_(
c[
"db_connection_history_table"].str())
 
   45     , db_addon_authors_table_(
c[
"db_addon_authors_table"].str())
 
   49         account_ = mariadb::account::create(
c[
"db_host"].str(), 
c[
"db_user"].str(), 
c[
"db_password"].str());
 
   50         account_->set_connect_option(mysql_option::MYSQL_SET_CHARSET_NAME, std::string(
"utf8mb4"));
 
   51         account_->set_schema(
c[
"db_name"].str());
 
   53         connection_ = create_connection();
 
   55     catch(
const mariadb::exception::base& 
e)
 
   57         log_sql_exception(
"Failed to connect to the database!", 
e);
 
   63     ERR_SQL << text << 
'\n' 
   64             << 
"what: " << 
e.what() << 
'\n' 
   65             << 
"error id: " << 
e.error_id();
 
   70     return mariadb::connection::create(
account_);
 
   78     std::string sql = 
"with recursive TEST(T) as " 
   82                       "select T+1 from TEST where T < ? " 
   84                       "select count(*) from TEST";
 
   95     catch(
const mariadb::exception::base& 
e)
 
  113         while(rslt->next()) {
 
  114             text += 
"\n" + rslt->get_string(
"TEXT");
 
  118     catch(
const mariadb::exception::base& 
e)
 
  125 std::unique_ptr<simple_wml::document> 
dbconn::get_game_history(
int player_id, 
int offset, std::string search_game_name, 
int search_content_type, std::string search_content)
 
  127     auto game_history_handler = [](
const mariadb::result_set_ref& rslt) {
 
  132             config& child = 
c.add_child(
"game");
 
  133             child[
"game_name"] = rslt->get_string(
"GAME_NAME");
 
  134             child[
"game_start"] = rslt->get_date_time(
"START_TIME").str();
 
  135             child[
"scenario_name"] = rslt->get_string(
"SCENARIO_NAME");
 
  136             child[
"era_name"] = rslt->get_string(
"ERA_NAME");
 
  137             for(
const auto& player_info : 
utils::split(rslt->get_string(
"PLAYERS")))
 
  143                     pchild[
"name"] = 
info[0];
 
  144                     pchild[
"faction"] = 
info[1];
 
  148                     ERR_SQL << 
"Expected player information to split into two fields, instead found the value `" << player_info << 
"`.";
 
  151             for(
const std::string& mod : 
utils::split(rslt->get_string(
"MODIFICATION_NAMES")))
 
  154                 mchild[
"name"] = mod;
 
  156             child[
"replay_url"] = rslt->get_string(
"REPLAY_URL");
 
  157             child[
"version"] = rslt->get_string(
"VERSION");
 
  166         if(player_id == 0 && search_game_name.empty() && search_content.empty())
 
  168             ERR_SQL << 
"Skipping game history query due to lack of search parameters.";
 
  169             auto doc = std::make_unique<simple_wml::document>();
 
  170             doc->set_attr(
"error", 
"No search parameters provided.");
 
  176         std::string game_history_query = 
"select " 
  179 "  GROUP_CONCAT(CONCAT(player.USER_NAME, ':', player.FACTION)) as PLAYERS, " 
  180 "  IFNULL(scenario.NAME, '') as SCENARIO_NAME, " 
  181 "  IFNULL(era.NAME, '') as ERA_NAME, " 
  182 "  IFNULL((select GROUP_CONCAT(distinct mods.NAME) from "+
db_game_content_info_table_+
" mods where mods.TYPE = 'modification' and mods.INSTANCE_UUID = game.INSTANCE_UUID and mods.GAME_ID = game.GAME_ID), '') as MODIFICATION_NAMES, " 
  184 "  when game.PUBLIC = 1 and game.INSTANCE_VERSION != 'trunk' " 
  185 "  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) " 
  186 "  when game.PUBLIC = 1 and game.INSTANCE_VERSION = 'trunk' " 
  187 "  then concat('https://replays.wesnoth.org/', game.INSTANCE_VERSION, '/', year(game.END_TIME), '/', lpad(month(game.END_TIME), 2, '0'), '/', lpad(day(game.END_TIME), 2, '0'), '/', game.REPLAY_NAME) " 
  189 "  end as REPLAY_URL, " 
  191 "  when game.INSTANCE_VERSION != 'trunk' " 
  192 "  then SUBSTRING(game.INSTANCE_VERSION, 1, 4) " 
  197     if(search_content_type == 2 && !search_content.empty())
 
  200 "  where mods.TYPE = 'modification' " 
  201 "  and mods.INSTANCE_UUID = game.INSTANCE_UUID " 
  202 "  and mods.GAME_ID = game.GAME_ID " 
  203 "  and mods.ID like ? ";
 
  206         params.emplace_back(search_content);
 
  211         game_history_query += 
"where true ";
 
  214     game_history_query += 
"and exists " 
  218 "    where game.INSTANCE_UUID = player1.INSTANCE_UUID " 
  219 "      and game.GAME_ID = player1.GAME_ID ";
 
  223         game_history_query += 
" and player1.USER_ID = ? ";
 
  224         params.emplace_back(player_id);
 
  227     game_history_query += 
"  ) " 
  228 "  and game.INSTANCE_UUID = player.INSTANCE_UUID " 
  229 "  and game.GAME_ID = player.GAME_ID " 
  230 "  and player.USER_ID != -1 " 
  231 "  and game.END_TIME is not NULL " 
  232 "  and scenario.TYPE = 'scenario' " 
  233 "  and scenario.INSTANCE_UUID = game.INSTANCE_UUID " 
  234 "  and scenario.GAME_ID = game.GAME_ID " 
  235 "  and era.TYPE = 'era' " 
  236 "  and era.INSTANCE_UUID = game.INSTANCE_UUID " 
  237 "  and era.GAME_ID = game.GAME_ID ";
 
  239     if(!search_game_name.empty())
 
  241         game_history_query += 
"and game.GAME_NAME like ? ";
 
  244         params.emplace_back(search_game_name);
 
  248     if(search_content_type == 0 && !search_content.empty())
 
  250         game_history_query += 
"and scenario.ID like ? ";
 
  253         params.emplace_back(search_content);
 
  257     if(search_content_type == 1 && !search_content.empty())
 
  259         game_history_query += 
"and era.ID like ? ";
 
  262         params.emplace_back(search_content);
 
  265     game_history_query += 
"group by game.INSTANCE_UUID, game.GAME_ID, SCENARIO_NAME, ERA_NAME " 
  266 "order by game.START_TIME desc " 
  267 "limit 11 offset ? ";
 
  268         params.emplace_back(offset);
 
  270         DBG_SQL << 
"before getting connection for game history query for player " << player_id;
 
  274         DBG_SQL << 
"game history query text for player " << player_id << 
": " << game_history_query;
 
  278         DBG_SQL << 
"after game history query for player " << player_id;
 
  280         auto doc = std::make_unique<simple_wml::document>();
 
  284         for(
const auto& result : history.
child_range(
"game"))
 
  287             ghr.
set_attr_dup(
"game_name", result[
"game_name"].str().c_str());
 
  288             ghr.
set_attr_dup(
"game_start", result[
"game_start"].str().c_str());
 
  289             ghr.
set_attr_dup(
"scenario_name", result[
"scenario_name"].str().c_str());
 
  290             ghr.
set_attr_dup(
"era_name", result[
"era_name"].str().c_str());
 
  291             ghr.
set_attr_dup(
"replay_url", result[
"replay_url"].str().c_str());
 
  292             ghr.
set_attr_dup(
"version", result[
"version"].str().c_str());
 
  293             for(
const auto& player : result.child_range(
"player"))
 
  296                 p.set_attr_dup(
"name", player[
"name"].str().c_str());
 
  297                 p.set_attr_dup(
"faction", player[
"faction"].str().c_str());
 
  299             for(
const auto& mod : result.child_range(
"modification"))
 
  306         DBG_SQL << 
"after parsing results of game history query for player " << player_id;
 
  310     catch(
const mariadb::exception::base& 
e)
 
  312         log_sql_exception(
"Could not retrieve the game history for forum ID `"+std::to_string(player_id)+
"`!", 
e);
 
  313         auto doc = std::make_unique<simple_wml::document>();
 
  314         doc->set_attr(
"error", 
"Error retrieving game history.");
 
  325     catch(
const mariadb::exception::base& 
e)
 
  338     catch(
const mariadb::exception::base& 
e)
 
  351     catch(
const mariadb::exception::base& 
e)
 
  360     std::vector<std::string> group_params;
 
  363     params.emplace_back(name);
 
  364     for(
int group_id : group_ids) {
 
  365         group_params.emplace_back(
"?");
 
  366         params.emplace_back(group_id);
 
  374     catch(
const mariadb::exception::base& 
e)
 
  384     auto ban_info_handler = [](
const mariadb::result_set_ref& rslt) {
 
  388             c[
"ban_type"] = rslt->get_signed32(
"ban_type");
 
  389             c[
"ban_end"] = rslt->get_signed32(
"ban_end");
 
  390             c[
"user_id"] = rslt->get_signed32(
"ban_userid");
 
  391             c[
"email"] = rslt->get_string(
"ban_email");
 
  399         return get_complex_results(
connection_, &ban_info_handler, 
"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 >= ?)",
 
  400             { ip, name, name, std::chrono::system_clock::to_time_t(std::chrono::system_clock::now()) });
 
  402     catch(
const mariadb::exception::base& 
e)
 
  404         log_sql_exception(
"Failed to check ban info for user '"+name+
"' connecting from ip '"+ip+
"'!", 
e);
 
  409 std::string 
dbconn::get_user_string(
const std::string& table, 
const std::string& column, 
const std::string& name)
 
  415     catch(
const mariadb::exception::base& 
e)
 
  417         log_sql_exception(
"Unable to query column `"+column+
"` from table `"+table+
"` for user `"+name+
"`", 
e);
 
  421 int dbconn::get_user_int(
const std::string& table, 
const std::string& column, 
const std::string& name)
 
  425         return static_cast<int>(
get_single_long(
connection_, 
"SELECT `"+column+
"` from `"+table+
"` WHERE UPPER(username)=UPPER(?)", { name }));
 
  427     catch(
const mariadb::exception::base& 
e)
 
  429         log_sql_exception(
"Unable to query column `"+column+
"` from table `"+table+
"` for user `"+name+
"`", 
e);
 
  443     catch(
const mariadb::exception::base& 
e)
 
  449 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)
 
  453         modify(
connection_, 
"INSERT INTO `"+
db_game_info_table_+
"`(INSTANCE_UUID, GAME_ID, INSTANCE_VERSION, GAME_NAME, RELOAD, OBSERVERS, PUBLIC, PASSWORD) VALUES(?, ?, ?, ?, ?, ?, ?, ?)",
 
  454             { uuid, game_id, version, name, reload, observers, is_public, has_password });
 
  456     catch(
const mariadb::exception::base& 
e)
 
  458         log_sql_exception(
"Failed to insert game info row for UUID `"+uuid+
"` and game ID `"+std::to_string(game_id)+
"`", 
e);
 
  466             { replay_location, uuid, game_id });
 
  468     catch(
const mariadb::exception::base& 
e)
 
  470         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);
 
  473 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, 
const std::string& leaders)
 
  477         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, LEADERS) VALUES(?, ?, IFNULL((SELECT user_id FROM `"+
db_users_table_+
"` WHERE username = ?), -1), ?, ?, ?, ?, ?, ?, ?)",
 
  478             { uuid, game_id, username, 
side_number, is_host, faction, version, source, current_user, leaders });
 
  480     catch(
const mariadb::exception::base& 
e)
 
  482         log_sql_exception(
"Failed to insert game player info row for UUID `"+uuid+
"` and game ID `"+std::to_string(game_id)+
"`", 
e);
 
  485 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& addon_id, 
const std::string& addon_version)
 
  489         return modify(
connection_, 
"INSERT INTO `"+
db_game_content_info_table_+
"`(INSTANCE_UUID, GAME_ID, TYPE, NAME, ID, ADDON_ID, ADDON_VERSION) VALUES(?, ?, ?, ?, ?, ?, ?)",
 
  490             { uuid, game_id, 
type, name, 
id, addon_id, addon_version });
 
  492     catch(
const mariadb::exception::base& 
e)
 
  494         log_sql_exception(
"Failed to insert game content info row for UUID `"+uuid+
"` and game ID `"+std::to_string(game_id)+
"`", 
e);
 
  505     catch(
const mariadb::exception::base& 
e)
 
  507         log_sql_exception(
"Failed to set the OOS flag for UUID `"+uuid+
"` and game ID `"+std::to_string(game_id)+
"`", 
e);
 
  517     catch(
const mariadb::exception::base& 
e)
 
  519         log_sql_exception(
"Unable to check whether `"+std::to_string(topic_id)+
"` exists.", 
e);
 
  524 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, 
const std::string& uploader)
 
  528         modify(
connection_, 
"INSERT INTO `"+
db_addon_info_table_+
"`(INSTANCE_VERSION, ADDON_ID, ADDON_NAME, TYPE, VERSION, FORUM_AUTH, FEEDBACK_TOPIC, UPLOADER) VALUES(?, ?, ?, ?, ?, ?, ?, ?)",
 
  529             { instance_version, 
id, name, 
type, version, forum_auth, topic_id, uploader });
 
  531     catch(
const mariadb::exception::base& 
e)
 
  533         log_sql_exception(
"Unable to insert add-on info for add-on `"+
id+
"` for instance `"+instance_version+
"`.", 
e);
 
  537 unsigned long long dbconn::insert_login(
const std::string& username, 
const std::string& ip, 
const std::string& version)
 
  542             { username, ip, version });
 
  544     catch(
const mariadb::exception::base& 
e)
 
  546         log_sql_exception(
"Unable to insert login row user `"+username+
"` and ip `"+ip+
"`.", 
e);
 
  558     catch(
const mariadb::exception::base& 
e)
 
  568         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",
 
  571         *out << 
"\nCount of results for ip: " << rslt->row_count();
 
  575             *out << 
"\nFound user " << rslt->get_string(0) << 
" with ip " << rslt->get_string(1)
 
  576                  << 
", logged in at " << rslt->get_string(2) << 
" and logged out at " << rslt->get_string(3);
 
  579     catch(
const mariadb::exception::base& 
e)
 
  589         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",
 
  592         *out << 
"\nCount of results for user: " << rslt->row_count();
 
  596             *out << 
"\nFound user " << rslt->get_string(0) << 
" with ip " << rslt->get_string(1)
 
  597                  << 
", logged in at " << rslt->get_string(2) << 
" and logged out at " << rslt->get_string(3);
 
  600     catch(
const mariadb::exception::base& 
e)
 
  611             { instance_version, 
id, version });
 
  613     catch(
const mariadb::exception::base& 
e)
 
  615         log_sql_exception(
"Unable to update download count for add-on "+
id+
" with version "+version+
".", 
e);
 
  619 bool dbconn::is_user_author(
const std::string& instance_version, 
const std::string& 
id, 
const std::string& username, 
int is_primary) {
 
  623             { instance_version, 
id, username, is_primary });
 
  625     catch(
const mariadb::exception::base& 
e)
 
  627         log_sql_exception(
"Unable to check whether `"+username+
"` is an author of "+
id+
" for version "+instance_version+
".", 
e);
 
  636             { instance_version, 
id });
 
  638     catch(
const mariadb::exception::base& 
e)
 
  640         log_sql_exception(
"Unable to delete addon authors for "+
id+
" and version "+instance_version+
".", 
e);
 
  644 void dbconn::insert_addon_author(
const std::string& instance_version, 
const std::string& 
id, 
const std::string& author, 
int is_primary) {
 
  648             { instance_version, 
id, author, is_primary });
 
  650     catch(
const mariadb::exception::base& 
e)
 
  652         log_sql_exception(
"Unable to delete addon authors for "+
id+
" and version "+instance_version+
".", 
e);
 
  660             { instance_version, 
id });
 
  662     catch(
const mariadb::exception::base& 
e)
 
  664         log_sql_exception(
"Unable to check whether authors exist for "+
id+
" for version "+instance_version+
".", 
e);
 
  670     auto addon_downloads_handler = [](
const mariadb::result_set_ref& rslt) {
 
  673         while(rslt->next()) {
 
  674             config& child = 
c.add_child(
"download_info");
 
  675             child[
"name"] = rslt->get_string(
"ADDON_NAME");
 
  676             child[
"version"] = rslt->get_string(
"VERSION");
 
  677             child[
"uploaded"] = rslt->get_date_time(
"UPLOADED_ON").str();
 
  678             child[
"downloads"] = rslt->get_unsigned32(
"DOWNLOAD_COUNT");
 
  687             { instance_version, 
id });
 
  689     catch(
const mariadb::exception::base& 
e)
 
  697     auto forum_auth_usage_handler = [](
const mariadb::result_set_ref& rslt) {
 
  701             c[
"all_count"] = rslt->get_signed64(
"ALL_COUNT");
 
  702             c[
"forum_auth_count"] = rslt->get_signed64(
"FORUM_AUTH_COUNT");
 
  704             throw mariadb::exception::base(
"Count query somehow returned no rows!");
 
  713             "(select count(distinct ADDON_ID) from "+
db_addon_info_table_+
" where INSTANCE_VERSION = ? and FORUM_AUTH = 1) as FORUM_AUTH_COUNT from dual",
 
  714             { instance_version, instance_version });
 
  716     catch(
const mariadb::exception::base& 
e)
 
  724     auto addon_admin_handler = [](
const mariadb::result_set_ref& rslt) {
 
  727         while(rslt->next()) {
 
  728             config& child = 
c.add_child(
"admin");
 
  729             child[
"username"] = rslt->get_string(
"USERNAME");
 
  738             { site_admin_group, forum_admin_group });
 
  740     catch(
const mariadb::exception::base& 
e)
 
  742         log_sql_exception(
"Failed to get addon admins for groups '"+std::to_string(site_admin_group)+
"' and '"+std::to_string(forum_admin_group)+
"'!", 
e);
 
  750 template <
typename F>
 
  753     mariadb::result_set_ref rslt = 
select(connection, sql, params);
 
  762     mariadb::result_set_ref rslt = 
select(connection, sql, params);
 
  765         return rslt->get_string(0);
 
  769         throw mariadb::exception::base(
"No string value found in the database!");
 
  774     mariadb::result_set_ref rslt = 
select(connection, sql, params);
 
  780         switch(rslt->column_type(0))
 
  782             case mariadb::value::type::decimal:
 
  783                 return static_cast<long>(rslt->get_decimal(0).float32());
 
  784             case mariadb::value::type::unsigned8:
 
  785             case mariadb::value::type::signed8:
 
  786                 return rslt->get_signed8(0);
 
  787             case mariadb::value::type::unsigned16:
 
  788             case mariadb::value::type::signed16:
 
  789                 return rslt->get_signed16(0);
 
  790             case mariadb::value::type::unsigned32:
 
  791             case mariadb::value::type::signed32:
 
  792                 return rslt->get_signed32(0);
 
  793             case mariadb::value::type::unsigned64:
 
  794             case mariadb::value::type::signed64:
 
  795                 return rslt->get_signed64(0);
 
  797                 throw mariadb::exception::base(
"Value retrieved was not a long!");
 
  802         throw mariadb::exception::base(
"No long value found in the database!");
 
  807     mariadb::result_set_ref rslt = 
select(connection, sql, params);
 
  818         mariadb::statement_ref stmt = 
query(connection, sql, params);
 
  819         mariadb::result_set_ref rslt = mariadb::result_set_ref(stmt->query());
 
  822     catch(
const mariadb::exception::base& 
e)
 
  824         ERR_SQL << 
"SQL query failed for query: `"+sql+
"`";
 
  832         mariadb::statement_ref stmt = 
query(connection, sql, params);
 
  833         unsigned long long count = stmt->execute();
 
  836     catch(
const mariadb::exception::base& 
e)
 
  838         ERR_SQL << 
"SQL query failed for query: `"+sql+
"`";
 
  846         mariadb::statement_ref stmt = 
query(connection, sql, params);
 
  847         unsigned long long count = stmt->insert();
 
  850     catch(
const mariadb::exception::base& 
e)
 
  852         ERR_SQL << 
"SQL query failed for query: `"+sql+
"`";
 
  857 mariadb::statement_ref 
dbconn::query(
const mariadb::connection_ref& connection, 
const std::string& sql, 
const sql_parameters& params)
 
  859     mariadb::statement_ref stmt = connection->create_statement(sql);
 
  862     for(
const auto& param : params)
 
  864         std::visit([&
i, &stmt](
const auto& 
p) {
 
  865             using T = std::remove_cv_t<std::remove_reference_t<decltype(
p)>>;
 
  866             if constexpr (std::is_same_v<T, bool>) {
 
  867                 stmt->set_boolean(
i, 
p);
 
  868             } 
else if constexpr (std::is_same_v<T, int>) {
 
  869                 stmt->set_signed32(
i, 
p);
 
  870             } 
else if constexpr (std::is_same_v<T, long>) {
 
  871                 stmt->set_signed64(
i, 
p);
 
  872             } 
else if constexpr (std::is_same_v<T, unsigned long long>) {
 
  873                 stmt->set_signed64(
i, 
p);
 
  874             } 
else if constexpr (std::is_same_v<T, std::string>) {
 
  875                 stmt->set_string(
i, 
p);
 
  876             } 
else if constexpr (std::is_same_v<T, const char*>) {
 
  877                 stmt->set_string(
i, 
p);
 
  879                 static_assert(utils::dependent_false_v<T>, 
"Unsupported parameter type in SQL query");
 
A config object defines a single node in a WML file, with access to child nodes.
config & add_child(std::string_view key)
child_itors child_range(std::string_view key)
void delete_addon_authors(const std::string &instance_version, const std::string &id)
void insert_addon_author(const std::string &instance_version, const std::string &id, const std::string &author, int is_primary)
bool do_any_authors_exist(const std::string &instance_version, const std::string &id)
void update_addon_download_count(const std::string &instance_version, const std::string &id, const std::string &version)
config get_addon_downloads_info(const std::string &instance_version, const std::string &id)
std::string db_tournament_query_
The text of the SQL query to use to retrieve any currently active tournaments.
bool topic_id_exists(int topic_id)
bool is_user_in_groups(const std::string &name, const std::vector< int > &group_ids)
int async_test_query(int limit)
bool is_user_author(const std::string &instance_version, const std::string &id, const std::string &username, int is_primary)
mariadb::connection_ref connection_
The actual connection to the database.
bool exists(const mariadb::connection_ref &connection, const std::string &sql, const sql_parameters ¶ms)
long get_forum_id(const std::string &name)
config get_addon_admins(int site_admin_group, int forum_admin_group)
std::unique_ptr< simple_wml::document > get_game_history(int player_id, int offset, std::string search_game_name, int search_content_type, std::string search_content)
This is an asynchronous query that is executed on a separate connection to retrieve the game history ...
void get_ips_for_user(const std::string &username, std::ostringstream *out)
std::string db_addon_authors_table_
The name of the table that contains the add-on authors information.
bool user_exists(const std::string &name)
void get_users_for_ip(const std::string &ip, std::ostringstream *out)
long get_single_long(const mariadb::connection_ref &connection, const std::string &sql, const sql_parameters ¶ms)
std::string get_single_string(const mariadb::connection_ref &connection, const std::string &sql, const sql_parameters ¶ms)
std::string db_banlist_table_
The name of the table that contains forum ban information.
config get_complex_results(const mariadb::connection_ref &connection, F *handler, const std::string &sql, const sql_parameters ¶ms)
unsigned long long insert_login(const std::string &username, const std::string &ip, const std::string &version)
mariadb::connection_ref create_connection()
Creates a new connection object from the account.
std::string db_extra_table_
The name of the table that contains additional user information.
void update_logout(unsigned long long login_id)
std::string db_addon_info_table_
The name of the table that contains add-on information.
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.
std::string db_game_content_info_table_
The name of the table that contains game content information.
bool extra_row_exists(const std::string &name)
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.
std::string db_user_group_table_
The name of the table that contains forum group information.
mariadb::account_ref account_
The account used to connect to the database.
config get_ban_info(const std::string &name, const std::string &ip)
void set_oos_flag(const std::string &uuid, int game_id)
void update_game_end(const std::string &uuid, int game_id, const std::string &replay_location)
std::string db_game_info_table_
The name of the table that contains game-level information.
std::string db_game_player_info_table_
The name of the table that contains player-level information per game.
mariadb::statement_ref query(const mariadb::connection_ref &connection, const std::string &sql, const sql_parameters ¶ms)
For a given connection, set the provided SQL and parameters on a statement.
std::string db_connection_history_table_
The name of the table that contains user connection history.
int get_user_int(const std::string &table, const std::string &column, const std::string &name)
unsigned long long modify(const mariadb::connection_ref &connection, const std::string &sql, const sql_parameters ¶ms)
Executes non-select statements (ie: insert, update, delete).
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, const std::string &uploader)
unsigned long long modify_get_id(const mariadb::connection_ref &connection, const std::string &sql, const sql_parameters ¶ms)
Executes non-select statements (ie: insert, update, delete), but primarily intended for inserts that ...
std::string db_topics_table_
The name of the table that contains phpbb forum thread information.
std::string get_user_string(const std::string &table, const std::string &column, const std::string &name)
std::string db_users_table_
The name of the table that contains forum user information.
dbconn(const config &c)
Initializes the synchronous query connection as well as the account object that has the connection se...
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)
config get_forum_auth_usage(const std::string &instance_version)
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 ¤t_user, const std::string &leaders)
mariadb::result_set_ref select(const mariadb::connection_ref &connection, const std::string &sql, const sql_parameters ¶ms)
Executes a select statement.
std::string get_tournaments()
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 &addon_id, const std::string &addon_version)
node & add_child(const char *name)
node & set_attr_dup(const char *key, const char *value)
std::vector< std::variant< bool, int, long, unsigned long long, std::string, const char * > > sql_parameters
std::string id
Text to match against addon_info.tags()
std::string lowercase(std::string_view s)
Returns a lowercased version of the string.
void to_sql_wildcards(std::string &str, bool underscores)
Converts '*' to '' and optionally escapes '_'.
std::string join(const T &v, const std::string &s=",")
Generates a new string joining container items in a list.
std::vector< std::string > split(const config_attribute_value &val)