Rewrote queries to support ONLY_FULL_GROUP_BY (#764).

This commit is contained in:
shavit 2019-03-27 10:27:50 +02:00
parent 4d2308ef1f
commit 12005e8c18
5 changed files with 66 additions and 70 deletions

View File

@ -1347,7 +1347,7 @@ void SQL_DBConnect()
gS_MySQLPrefix);
}
gH_SQL.Query(SQL_CreateTable_Callback, sQuery, 0, DBPrio_High);
gH_SQL.Query(SQL_CreateTable_Callback, sQuery);
}
}

View File

@ -698,14 +698,14 @@ void DeleteUserData(int client, const char[] sAuthID3)
{
char sQueryGetWorldRecords[256];
FormatEx(sQueryGetWorldRecords, 256,
"SELECT map, id, style, track FROM %splayertimes WHERE auth = '%s' GROUP BY map, style, track;",
"SELECT map, id, style, track FROM %splayertimes WHERE auth = '%s';",
gS_MySQLPrefix, sAuthID3);
DataPack pack = new DataPack();
pack.WriteCell(client);
pack.WriteString(sAuthID3);
DataPack hPack = new DataPack();
hPack.WriteCell(client);
hPack.WriteString(sAuthID3);
gH_SQL.Query(SQL_DeleteUserData_GetRecords_Callback, sQueryGetWorldRecords, pack, DBPrio_High);
gH_SQL.Query(SQL_DeleteUserData_GetRecords_Callback, sQueryGetWorldRecords, hPack, DBPrio_High);
}
else
@ -725,13 +725,13 @@ void DeleteUserData(int client, const char[] sAuthID3)
public void SQL_DeleteUserData_GetRecords_Callback(Database db, DBResultSet results, const char[] error, any data)
{
DataPack pack = view_as<DataPack>(data);
pack.Reset();
int client = pack.ReadCell();
DataPack hPack = view_as<DataPack>(data);
hPack.Reset();
int client = hPack.ReadCell();
char sAuthID3[32];
pack.ReadString(sAuthID3, 32);
delete pack;
hPack.ReadString(sAuthID3, 32);
delete hPack;
if(results == null)
{
@ -740,7 +740,7 @@ public void SQL_DeleteUserData_GetRecords_Callback(Database db, DBResultSet resu
return;
}
Transaction trans = new Transaction();
Transaction hTransaction = new Transaction();
while(results.FetchRow())
{
@ -756,20 +756,20 @@ public void SQL_DeleteUserData_GetRecords_Callback(Database db, DBResultSet resu
"SELECT id FROM %splayertimes WHERE map = '%s' AND style = %d AND track = %d ORDER BY time LIMIT 1;",
gS_MySQLPrefix, map, style, track);
DataPack transPack = new DataPack();
transPack.WriteString(map);
transPack.WriteCell(id);
transPack.WriteCell(style);
transPack.WriteCell(track);
DataPack hTransPack = new DataPack();
hTransPack.WriteString(map);
hTransPack.WriteCell(id);
hTransPack.WriteCell(style);
hTransPack.WriteCell(track);
trans.AddQuery(sQueryGetWorldRecordID, transPack);
hTransaction.AddQuery(sQueryGetWorldRecordID, hTransPack);
}
DataPack steamPack = new DataPack();
steamPack.WriteString(sAuthID3);
steamPack.WriteCell(client);
gH_SQL.Execute(trans, Trans_OnRecordCompare, INVALID_FUNCTION, steamPack, DBPrio_High);
gH_SQL.Execute(hTransaction, Trans_OnRecordCompare, INVALID_FUNCTION, steamPack, DBPrio_High);
}
public void Trans_OnRecordCompare(Database db, any data, int numQueries, DBResultSet[] results, any[] queryData)
@ -2139,8 +2139,7 @@ void SQL_DBConnect()
FormatEx(sQuery, 512, "CREATE TABLE IF NOT EXISTS `%susers` (`auth` VARCHAR(32) NOT NULL PRIMARY KEY, `name` VARCHAR(32), `country` VARCHAR(32), `ip` VARCHAR(64), `lastlogin` INTEGER NOT NULL DEFAULT -1, `points` FLOAT NOT NULL DEFAULT 0);", gS_MySQLPrefix);
}
// CREATE TABLE IF NOT EXISTS
gH_SQL.Query(SQL_CreateTable_Callback, sQuery);
gH_SQL.Query(SQL_CreateTable_Callback, sQuery, 0, DBPrio_High);
}
public void SQL_CreateTable_Callback(Database db, DBResultSet results, const char[] error, any data)

View File

@ -787,7 +787,7 @@ void UpdateAllPoints()
#endif
char sQuery[128];
FormatEx(sQuery, 128, "UPDATE %susers SET points = GetWeightedPoints(auth) WHERE auth IN (SELECT auth FROM %splayertimes GROUP BY auth);",
FormatEx(sQuery, 128, "UPDATE %susers SET points = GetWeightedPoints(auth) WHERE auth IN (SELECT DISTINCT auth FROM %splayertimes);",
gS_MySQLPrefix, gS_MySQLPrefix);
gH_SQL.Query(SQL_UpdateAllPoints_Callback, sQuery);
@ -815,7 +815,7 @@ void UpdatePlayerRank(int client, bool first)
// if there's any issue with this query,
// add "ORDER BY points DESC " before "LIMIT 1"
char sQuery[512];
FormatEx(sQuery, 512, "SELECT p.points, COUNT(*) rank FROM %susers u JOIN (SELECT points FROM %susers WHERE auth = '%s' LIMIT 1) p WHERE u.points >= p.points LIMIT 1;",
FormatEx(sQuery, 512, "SELECT u2.points, COUNT(*) FROM %susers u1 JOIN (SELECT points FROM %susers WHERE auth = '%s') u2 WHERE u1.points >= u2.points;",
gS_MySQLPrefix, gS_MySQLPrefix, sAuthID);
DataPack hPack = new DataPack();

View File

@ -491,21 +491,21 @@ Action OpenStatsMenu(int client, const char[] authid)
if(gB_Rankings)
{
FormatEx(sQuery, 2048, "SELECT a.clears, b.maps, c.wrs, d.name, d.country, d.lastlogin, d.points, e.rank FROM " ...
"(SELECT COUNT(*) clears FROM (SELECT id FROM %splayertimes WHERE auth = '%s' AND track = 0 GROUP BY map) s) a " ...
"JOIN (SELECT COUNT(*) maps FROM (SELECT id FROM %smapzones WHERE track = 0 AND type = 0 GROUP BY map) s) b " ...
"(SELECT COUNT(*) clears FROM (SELECT map FROM %splayertimes WHERE auth = '%s' AND track = 0 GROUP BY map) s) a " ...
"JOIN (SELECT COUNT(*) maps FROM (SELECT map FROM %smapzones WHERE track = 0 AND type = 0 GROUP BY map) s) b " ...
"JOIN (SELECT COUNT(*) wrs FROM %splayertimes a JOIN (SELECT MIN(time) time, map FROM %splayertimes WHERE style = 0 AND track = 0 GROUP by map, style, track) b ON a.time = b.time AND a.map = b.map AND track = 0 AND style = 0 WHERE auth = '%s') c " ...
"JOIN (SELECT name, country, lastlogin, FORMAT(points, 2) points FROM %susers WHERE auth = '%s' LIMIT 1) d " ...
"JOIN (SELECT FORMAT(COUNT(*), 0) rank FROM %susers WHERE points >= (SELECT points FROM %susers WHERE auth = '%s' LIMIT 1) ORDER BY points DESC) e " ...
"JOIN (SELECT name, country, lastlogin, FORMAT(points, 2) points FROM %susers WHERE auth = '%s') d " ...
"JOIN (SELECT COUNT(*) rank FROM %susers u1 JOIN (SELECT points FROM %susers WHERE auth = '%s') u2 WHERE u1.points >= u2.points) e " ...
"LIMIT 1;", gS_MySQLPrefix, authid, gS_MySQLPrefix, gS_MySQLPrefix, gS_MySQLPrefix, authid, gS_MySQLPrefix, authid, gS_MySQLPrefix, gS_MySQLPrefix, authid);
}
else
{
FormatEx(sQuery, 2048, "SELECT a.clears, b.maps, c.wrs, d.name, d.country, d.lastlogin FROM " ...
"(SELECT COUNT(*) clears FROM (SELECT id FROM %splayertimes WHERE auth = '%s' AND track = 0 GROUP BY map) s) a " ...
"JOIN (SELECT COUNT(*) maps FROM (SELECT id FROM %smapzones WHERE track = 0 AND type = 0 GROUP BY map) s) b " ...
"(SELECT COUNT(*) clears FROM (SELECT map FROM %splayertimes WHERE auth = '%s' AND track = 0 GROUP BY map) s) a " ...
"JOIN (SELECT COUNT(*) maps FROM (SELECT map FROM %smapzones WHERE track = 0 AND type = 0 GROUP BY map) s) b " ...
"JOIN (SELECT COUNT(*) wrs FROM %splayertimes a JOIN (SELECT MIN(time) time, map FROM %splayertimes WHERE style = 0 AND track = 0 GROUP by map, style, track) b ON a.time = b.time AND a.map = b.map AND track = 0 AND style = 0 WHERE auth = '%s') c " ...
"JOIN (SELECT name, country, lastlogin FROM %susers WHERE auth = '%s' LIMIT 1) d " ...
"JOIN (SELECT name, country, lastlogin FROM %susers WHERE auth = '%s') d " ...
"LIMIT 1;", gS_MySQLPrefix, authid, gS_MySQLPrefix, gS_MySQLPrefix, gS_MySQLPrefix, authid, gS_MySQLPrefix, authid);
}
@ -721,7 +721,7 @@ void ShowMaps(int client)
if(gI_MapType[client] == MAPSDONE)
{
FormatEx(sQuery, 512,
"SELECT a.map, a.time, a.jumps, a.id, COUNT(b.map) + 1 rank, a.points FROM %splayertimes a LEFT JOIN %splayertimes b ON a.time > b.time AND a.map = b.map AND a.style = b.style AND a.track = b.track WHERE a.auth = '%s' AND a.style = %d AND a.track = %d GROUP BY a.map ORDER BY a.%s;",
"SELECT a.map, a.time, a.jumps, a.id, COUNT(b.map) + 1 rank, a.points FROM %splayertimes a LEFT JOIN %splayertimes b ON a.time > b.time AND a.map = b.map AND a.style = b.style AND a.track = b.track WHERE a.auth = '%s' AND a.style = %d AND a.track = %d GROUP BY a.map, a.time, a.jumps, a.id, a.points ORDER BY a.%s;",
gS_MySQLPrefix, gS_MySQLPrefix, gS_TargetAuth[client], gI_Style[client], gI_Track[client], (gB_Rankings)? "points DESC":"map");
}

View File

@ -467,18 +467,22 @@ public void SQL_UpdateCache_Callback(Database db, DBResultSet results, const cha
void UpdateWRCache()
{
char sQuery[512];
// thanks Ollie Jones from stackoverflow! http://stackoverflow.com/a/36239523/5335680
// was a bit confused with this one :s
if(gB_MySQL)
{
FormatEx(sQuery, 512, "SELECT p.style, p.id, TRUNCATE(LEAST(s.time, p.time), 3), u.name, p.track FROM %splayertimes p JOIN(SELECT style, MIN(time) time, map, track FROM %splayertimes WHERE map = '%s' GROUP BY style, track ORDER BY date ASC) s ON p.style = s.style AND p.time = s.time AND p.map = s.map JOIN %susers u ON p.auth = u.auth GROUP BY p.style, p.track ORDER BY date ASC;", gS_MySQLPrefix, gS_MySQLPrefix, gS_Map, gS_MySQLPrefix);
FormatEx(sQuery, 512,
"SELECT p1.id, p1.style, p1.track, p1.time, u.name FROM %splayertimes p1 " ...
"JOIN (SELECT style, track, MIN(time) time FROM %splayertimes WHERE map = '%s' GROUP BY style, track) p2 " ...
"JOIN %susers u ON p1.style = p2.style AND p1.track = p2.track AND p1.time = p2.time AND u.auth = p1.auth " ...
"WHERE p1.map = '%s';",
gS_MySQLPrefix, gS_MySQLPrefix, gS_Map, gS_MySQLPrefix, gS_Map);
}
// sorry, LEAST() isn't available for SQLITE!
else
{
FormatEx(sQuery, 512, "SELECT p.style, p.id, s.time, u.name, p.track FROM %splayertimes p JOIN(SELECT style, MIN(time) time, map, track FROM %splayertimes WHERE map = '%s' GROUP BY style, track) s ON p.style = s.style AND p.time = s.time AND p.map = s.map AND s.track = p.track JOIN %susers u ON p.auth = u.auth GROUP BY p.style, p.track;", gS_MySQLPrefix, gS_MySQLPrefix, gS_Map, gS_MySQLPrefix);
FormatEx(sQuery, 512,
"SELECT p.id, p.style, p.track, s.time, u.name FROM %splayertimes p JOIN(SELECT style, MIN(time) time, map, track FROM %splayertimes WHERE map = '%s' GROUP BY style, track) s ON p.style = s.style AND p.time = s.time AND p.map = s.map AND s.track = p.track JOIN %susers u ON p.auth = u.auth GROUP BY p.style, p.track;",
gS_MySQLPrefix, gS_MySQLPrefix, gS_Map, gS_MySQLPrefix);
}
gH_SQL.Query(SQL_UpdateWRCache_Callback, sQuery, 0, DBPrio_Low);
@ -507,19 +511,18 @@ public void SQL_UpdateWRCache_Callback(Database db, DBResultSet results, const c
// setup cache again, dynamically and not hardcoded
while(results.FetchRow())
{
int style = results.FetchInt(0);
int iStyle = results.FetchInt(1);
int iTrack = results.FetchInt(2);
if(style >= gI_Styles || style < 0 || gA_StyleSettings[style].bUnranked)
if(iStyle >= gI_Styles || iStyle < 0 || gA_StyleSettings[iStyle].bUnranked)
{
continue;
}
int track = results.FetchInt(4);
gI_WRRecordID[style][track] = results.FetchInt(1);
gF_WRTime[style][track] = results.FetchFloat(2);
results.FetchString(3, gS_WRName[style][track], MAX_NAME_LENGTH);
ReplaceString(gS_WRName[style][track], MAX_NAME_LENGTH, "#", "?");
gI_WRRecordID[iStyle][iTrack] = results.FetchInt(0);
gF_WRTime[iStyle][iTrack] = results.FetchFloat(3);
results.FetchString(4, gS_WRName[iStyle][iTrack], MAX_NAME_LENGTH);
ReplaceString(gS_WRName[iStyle][iTrack], MAX_NAME_LENGTH, "#", "?");
}
UpdateLeaderboards();
@ -635,7 +638,7 @@ public Action Command_Junk(int client, int args)
char sAuth[32];
GetClientAuthId(client, AuthId_Steam3, sAuth, 32);
FormatEx(sQuery, 256, "INSERT INTO %splayertimes (auth, map, time, jumps, date, style, strafes, sync) VALUES ('%s', '%s', %.03f, %d, %d, 0, %d, %.02f);", gS_MySQLPrefix, sAuth, gS_Map, GetRandomFloat(10.0, 20.0), GetRandomInt(5, 15), GetTime(), GetRandomInt(5, 15), GetRandomFloat(50.0, 99.99));
FormatEx(sQuery, 256, "INSERT INTO %splayertimes (auth, map, time, jumps, date, style, strafes, sync) VALUES ('%s', '%s', %f, %d, %d, 0, %d, %.02f);", gS_MySQLPrefix, sAuth, gS_Map, GetRandomFloat(10.0, 20.0), GetRandomInt(5, 15), GetTime(), GetRandomInt(5, 15), GetRandomFloat(50.0, 99.99));
SQL_LockDatabase(gH_SQL);
SQL_FastQuery(gH_SQL, sQuery);
@ -1566,10 +1569,10 @@ public Action Command_RecentRecords(int client, int args)
char sQuery[512];
FormatEx(sQuery, 512,
"SELECT a.id, a.map, u.name, a.time, a.jumps, a.style, a.points, a.track FROM %splayertimes a " ...
"JOIN (SELECT MIN(time) time, map, style, track FROM %splayertimes GROUP by map, style, track) b " ...
"JOIN %susers u ON a.time = b.time AND a.auth = u.auth AND a.map = b.map AND a.style = b.style AND a.track = b.track " ...
"ORDER BY date DESC LIMIT 100;", gS_MySQLPrefix, gS_MySQLPrefix, gS_MySQLPrefix);
"SELECT a.id, a.map, u.name, a.time, a.style, a.track FROM %splayertimes a " ...
"JOIN (SELECT MIN(time) time, map, style, track FROM %splayertimes GROUP by map, style, track ORDER BY date DESC) b " ...
"JOIN %susers u ON a.time = b.time AND a.auth = u.auth AND a.map = b.map AND a.style = b.style AND a.track = b.track " ...
"LIMIT 100;", gS_MySQLPrefix, gS_MySQLPrefix, gS_MySQLPrefix);
gH_SQL.Query(SQL_RR_Callback, sQuery, GetClientSerial(client), DBPrio_Low);
@ -1607,33 +1610,27 @@ public void SQL_RR_Callback(Database db, DBResultSet results, const char[] error
char sName[MAX_NAME_LENGTH];
results.FetchString(2, sName, 10);
if(strlen(sName) == 9)
if(strlen(sName) >= 9)
{
Format(sName, MAX_NAME_LENGTH, "%s...", sName);
}
char sTime[16];
float time = results.FetchFloat(3);
FormatSeconds(time, sTime, 16);
float fTime = results.FetchFloat(3);
FormatSeconds(fTime, sTime, 16);
int jumps = results.FetchInt(4);
int style = results.FetchInt(5);
float fPoints = results.FetchFloat(6);
int iStyle = results.FetchInt(4);
if(iStyle >= gI_Styles || iStyle < 0 || gA_StyleSettings[iStyle].bUnranked)
{
continue;
}
char sTrack[32];
GetTrackName(client, results.FetchInt(7), sTrack, 32);
GetTrackName(client, results.FetchInt(5), sTrack, 32);
char sDisplay[192];
if(gB_Rankings && fPoints > 0.0)
{
FormatEx(sDisplay, 192, "[%s, %c] %s - %s @ %s (%.03f %T)", gS_StyleStrings[style].sShortName, sTrack[0], sMap, sName, sTime, fPoints, "WRPoints", client);
}
else
{
FormatEx(sDisplay, 192, "[%s, %c] %s - %s @ %s (%d %T)", gS_StyleStrings[style].sShortName, sTrack[0], sMap, sName, sTime, jumps, "WRJumps", client);
}
FormatEx(sDisplay, 192, "[%s/%c] %s - %s @ %s", gS_StyleStrings[iStyle].sShortName, sTrack[0], sMap, sName, sTime);
char sInfo[192];
FormatEx(sInfo, 192, "%d;%s", results.FetchInt(0), sMap);
@ -1964,7 +1961,7 @@ void SQL_DBConnect()
gS_MySQLPrefix);
}
gH_SQL.Query(SQL_CreateTable_Callback, sQuery, 0, DBPrio_High);
gH_SQL.Query(SQL_CreateTable_Callback, sQuery);
}
public void SQL_CreateTable_Callback(Database db, DBResultSet results, const char[] error, any data)
@ -2088,14 +2085,14 @@ public void Shavit_OnFinish(int client, int style, float time, int jumps, int st
return;
}
FormatEx(sQuery, 512, "INSERT INTO %splayertimes (auth, map, time, jumps, date, style, strafes, sync, points, track, perfs) VALUES ('%s', '%s', %.03f, %d, %d, %d, %d, %.2f, 0.0, %d, %.2f);", gS_MySQLPrefix, sAuthID, gS_Map, time, jumps, GetTime(), style, strafes, sync, track, perfs);
FormatEx(sQuery, 512, "INSERT INTO %splayertimes (auth, map, time, jumps, date, style, strafes, sync, points, track, perfs) VALUES ('%s', '%s', %f, %d, %d, %d, %d, %.2f, 0.0, %d, %.2f);", gS_MySQLPrefix, sAuthID, gS_Map, time, jumps, GetTime(), style, strafes, sync, track, perfs);
}
else // update
{
Shavit_PrintToChatAll("%s[%s]%s %T", gS_ChatStrings.sVariable, sTrack, gS_ChatStrings.sText, "NotFirstCompletion", LANG_SERVER, gS_ChatStrings.sVariable2, client, gS_ChatStrings.sText, gS_ChatStrings.sStyle, gS_StyleStrings[style].sStyleName, gS_ChatStrings.sText, gS_ChatStrings.sVariable2, sTime, gS_ChatStrings.sText, gS_ChatStrings.sVariable, iRank, gS_ChatStrings.sText, jumps, strafes, sSync, gS_ChatStrings.sText, gS_ChatStrings.sWarning, sDifference);
FormatEx(sQuery, 512, "UPDATE %splayertimes SET time = %.03f, jumps = %d, date = %d, strafes = %d, sync = %.02f, points = 0.0, perfs = %.2f WHERE map = '%s' AND auth = '%s' AND style = %d AND track = %d;", gS_MySQLPrefix, time, jumps, GetTime(), strafes, sync, perfs, gS_Map, sAuthID, style, track);
FormatEx(sQuery, 512, "UPDATE %splayertimes SET time = %f, jumps = %d, date = %d, strafes = %d, sync = %.02f, points = 0.0, perfs = %.2f WHERE map = '%s' AND auth = '%s' AND style = %d AND track = %d;", gS_MySQLPrefix, time, jumps, GetTime(), strafes, sync, perfs, gS_Map, sAuthID, style, track);
}
gH_SQL.Query(SQL_OnFinish_Callback, sQuery, GetClientSerial(client), DBPrio_High);