/************************************************************************************* Copyright 2010 Philip Waldron This file is part of BayRate. BayRate 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 3 of the License, or (at your option) any later version. BayRate 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 BayRate. If not, see . ***************************************************************************************/ #include #include #include #include #include #include #include #include #include #include "db.h" #include "collection.h" #include "player.h" #include "game.h" using namespace std; databaseConnection::databaseConnection() { } databaseConnection::~databaseConnection() { db.disconnect(); } /**************************************************************** makeConnection () Establish a connection to the ratings server(s). *****************************************************************/ bool databaseConnection::makeConnection() { db = mysqlpp::Connection(false); return db.connect("database", "localhost", "user", "password");; } // Set exclude flags on any games for which player rank data is bogus // Bogus ranks are anything that isn't a kyu/dan indicator // Blank ranks will be dealt with later void databaseConnection::excludeBogusGameData() { mysqlpp::Query query(&db, false); query.exec("UPDATE games SET exclude = 1 WHERE NOT (rank_1 LIKE '%k%' OR rank_1 LIKE '%K%' OR rank_1 LIKE '%d%' OR rank_1 LIKE '%D%')"); query.exec("UPDATE games SET exclude = 1 WHERE NOT (rank_2 LIKE '%k%' OR rank_2 LIKE '%K%' OR rank_2 LIKE '%d%' OR rank_2 LIKE '%D%')"); query.exec("UPDATE games SET exclude = 1 WHERE (rank_1 = '0k' OR rank_1 = '0K' OR rank_1 = '0d' OR rank_1 = '0D')"); query.exec("UPDATE games SET exclude = 1 WHERE (rank_2 = '0k' OR rank_2 = '0K' OR rank_2 = '0d' OR rank_2 = '0D')"); query.exec("UPDATE games SET exclude = 1 WHERE handicap>9"); query.exec("UPDATE games SET exclude = 1 WHERE handicap>=2 and komi>=10"); query.exec("UPDATE games SET exclude = 1 WHERE handicap>=2 and komi<=-10"); query.exec("UPDATE games SET exclude = 1 WHERE (handicap=0 or handicap=1) and komi<=-20"); query.exec("UPDATE games SET exclude = 1 WHERE (handicap=0 or handicap=1) and komi<=-20"); query.exec("UPDATE games SET exclude = 1 WHERE (game_date < '1900-01-01')"); query.exec("UPDATE games SET exclude = 1 WHERE pin_player_1 = 0 or pin_player_2 = 0"); } /**************************************************************** bool getTournamentUpdateList (vector tournamentUpdateList, date tournamentCascadeDate) Get the list of tournaments that need (re)rating. List of tournament codes is placed in parameter TournamentUpdateList. Date of first tournament that need rerating placed in parameter tournamentCascadeDate. Returns true if the operation was successful *****************************************************************/ bool databaseConnection::getTournamentUpdateList(vector &tournamentUpdateList, boost::gregorian::date &tournamentCascadeDate) { mysqlpp::Query query = db.query("SELECT MIN(Game_Date) AS date FROM games WHERE Game_Date>'1900-01-01' AND NOT (Online OR Exclude OR Rated)"); mysqlpp::StoreQueryResult res = query.store(); if (!res) return false; mysqlpp::Date tempDate = res[0]["date"]; // Check if the response was NULL. The date gets converted to 0000-00-00 if it is. if (tempDate == mysqlpp::Date("0000-00-00")) { return true; } tournamentCascadeDate = boost::gregorian::date(boost::gregorian::from_simple_string(tempDate.str())); mysqlpp::Query query2 = db.query("SELECT Tournament_Code FROM tournaments WHERE Tournament_Date>=%0q ORDER BY Tournament_Date"); query2.parse(); res = query2.store(tempDate); for (size_t i=0; i(res[i]["Tournament_Code"])); } return true; } /**************************************************************** bool getTDList () Gets the last valid TDList prior to the date given by parameter tournamentCascadeDate. Data placed into map parameter TdList. Returns true if the operation is successful *****************************************************************/ bool databaseConnection::getTDList(boost::gregorian::date &tournamentCascadeDate, map &tdList) { tdListEntry entry; mysqlpp::Query query = db.query("SELECT name, x.pin_player, x.rating, x.sigma, x.elab_date FROM ratings x, players, (SELECT MAX(elab_date) AS maxdate, pin_player FROM ratings WHERE elab_date < %0q GROUP BY pin_player) AS maxresults WHERE x.pin_player=maxresults.pin_player AND x.elab_date=maxresults.maxdate and x.pin_player=players.pin_player and x.pin_player!=0"); query.parse(); mysqlpp::StoreQueryResult res = query.store(mysqlpp::Date(boost::gregorian::to_iso_extended_string(tournamentCascadeDate))); if (!res) return false; for (size_t i=0; i> rankPartNumber >> rankPartKyuDan; if ( (rankPartKyuDan == 'k') || (rankPartKyuDan == 'K') ) { p.seed = -(rankPartNumber+0.5); } else if ( (rankPartKyuDan == 'd') || (rankPartKyuDan == 'd') ) { p.seed = rankPartNumber+0.5; } else { cout << "Fatal error: player " << gameRes[i]["pin_player_1"] << " unknown rank format: " << gameRes[i]["rank_1"] << endl; exit(1); } c.playerHash[p.id] = p; } p.id = gameRes[i]["pin_player_2"]; if (c.playerHash.find(p.id) == c.playerHash.end()) { ss.str(string(gameRes[i]["rank_2"])); ss >> rankPartNumber >> rankPartKyuDan; if ( (rankPartKyuDan == 'k') || (rankPartKyuDan == 'K') ) { p.seed = -(rankPartNumber+0.5); } else if ( (rankPartKyuDan == 'd') || (rankPartKyuDan == 'd') ) { p.seed = rankPartNumber+0.5; } else { cout << "Fatal error: player " << gameRes[i]["pin_player_2"] << " unknown rank format: " << gameRes[i]["rank_2"] << endl; exit(1); } c.playerHash[p.id] = p; } } return true; } /**************************************************************** void syncNewRatings (collection &c) Pushes new ratings into the ratings database and update appropriate indexes. *****************************************************************/ void databaseConnection::syncNewRatings (collection &c) { map::iterator playerIt = c.playerHash.begin(); mysqlpp::Transaction trans(db); mysqlpp::Query query1 = db.query("INSERT INTO ratings (pin_player, rating, sigma, elab_date) VALUES (%0q, %1q, %2q, %3q) ON DUPLICATE KEY UPDATE rating=%4q, sigma=%5q"); query1.parse(); mysqlpp::Query query4 = db.query("UPDATE players SET rating=%0q, sigma=%1q, elab_date=%2q WHERE pin_player=%3q"); query4.parse(); for (playerIt = c.playerHash.begin(); playerIt != c.playerHash.end(); playerIt++) { query1.execute(playerIt->second.id, playerIt->second.rating, playerIt->second.sigma, to_iso_extended_string(c.tournamentDate), playerIt->second.rating, playerIt->second.sigma); if (query1.errnum() != 0) { cerr << "Query failure in query1 (db.cpp). Rolling back transaction and exiting program" << endl; trans.rollback(); exit(1); } query4.execute(playerIt->second.rating, playerIt->second.sigma, to_iso_extended_string(c.tournamentDate), playerIt->second.id); if (query4.errnum() != 0) { cerr << "Query failure in query4 (db.cpp). Rolling back transaction and exiting program" << endl; trans.rollback(); exit(1); } } mysqlpp::Query query2 = db.query("UPDATE games SET elab_date = %0q WHERE tournament_code=%1q AND Online=0"); query2.parse(); query2.execute(to_iso_extended_string(c.tournamentDate), c.tournamentCode); if (query2.errnum() != 0) { cerr << "Query failure in query2 (db.cpp). Rolling back transaction and exiting program" << endl; trans.rollback(); exit(1); } mysqlpp::Query query3 = db.query("UPDATE games SET Rated=1 WHERE tournament_code=%0q AND Online=0"); query3.parse(); query3.execute(c.tournamentCode); if (query3.errnum() != 0) { cerr << "Query failure in (db.cpp). Rolling back transaction and exiting program" << endl; trans.rollback(); exit(1); } trans.commit(); }