This commit is contained in:
moemoequte 2025-09-30 23:33:39 +00:00 committed by GitHub
commit 3c228f3ad8
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 881 additions and 128 deletions

View File

@ -140,6 +140,12 @@ public void SQL_CreateTables(Database hSQL, const char[] prefix, int driver)
"CREATE TABLE IF NOT EXISTS `%susers` (`auth` INT NOT NULL, `name` VARCHAR(32) COLLATE 'utf8mb4_general_ci', `ip` INT, `lastlogin` INT NOT NULL DEFAULT -1, `firstlogin` INT NOT NULL DEFAULT -1, `points` FLOAT NOT NULL DEFAULT 0, `playtime` FLOAT NOT NULL DEFAULT 0, PRIMARY KEY (`auth`), INDEX `points` (`points`), INDEX `lastlogin` (`lastlogin`)) ENGINE=INNODB;", "CREATE TABLE IF NOT EXISTS `%susers` (`auth` INT NOT NULL, `name` VARCHAR(32) COLLATE 'utf8mb4_general_ci', `ip` INT, `lastlogin` INT NOT NULL DEFAULT -1, `firstlogin` INT NOT NULL DEFAULT -1, `points` FLOAT NOT NULL DEFAULT 0, `playtime` FLOAT NOT NULL DEFAULT 0, PRIMARY KEY (`auth`), INDEX `points` (`points`), INDEX `lastlogin` (`lastlogin`)) ENGINE=INNODB;",
gS_SQLPrefix); gS_SQLPrefix);
} }
else if (driver == Driver_pgsql)
{
FormatEx(sQuery, sizeof(sQuery),
"CREATE TABLE IF NOT EXISTS %susers (auth INT NOT NULL PRIMARY KEY, name VARCHAR(32), ip INT, lastlogin INT NOT NULL DEFAULT -1, firstlogin INT NOT NULL DEFAULT -1, points REAL NOT NULL DEFAULT 0, playtime REAL NOT NULL DEFAULT 0);",
gS_SQLPrefix);
}
else else
{ {
FormatEx(sQuery, sizeof(sQuery), FormatEx(sQuery, sizeof(sQuery),
@ -149,9 +155,24 @@ public void SQL_CreateTables(Database hSQL, const char[] prefix, int driver)
AddQueryLog(trans, sQuery); AddQueryLog(trans, sQuery);
FormatEx(sQuery, sizeof(sQuery), if (driver == Driver_mysql)
"CREATE TABLE IF NOT EXISTS `%smigrations` (`code` TINYINT NOT NULL, PRIMARY KEY (`code`));", {
gS_SQLPrefix); FormatEx(sQuery, sizeof(sQuery),
"CREATE TABLE IF NOT EXISTS `%smigrations` (`code` TINYINT NOT NULL, PRIMARY KEY (`code`));",
gS_SQLPrefix);
}
else if (driver == Driver_pgsql)
{
FormatEx(sQuery, sizeof(sQuery),
"CREATE TABLE IF NOT EXISTS %smigrations (code SMALLINT NOT NULL, PRIMARY KEY (code));",
gS_SQLPrefix);
}
else
{
FormatEx(sQuery, sizeof(sQuery),
"CREATE TABLE IF NOT EXISTS `%smigrations` (`code` TINYINT NOT NULL, PRIMARY KEY (`code`));",
gS_SQLPrefix);
}
AddQueryLog(trans, sQuery); AddQueryLog(trans, sQuery);
// //
@ -164,6 +185,12 @@ public void SQL_CreateTables(Database hSQL, const char[] prefix, int driver)
"CREATE TABLE IF NOT EXISTS `%schat` (`auth` INT NOT NULL, `name` INT NOT NULL DEFAULT 0, `ccname` VARCHAR(128) COLLATE 'utf8mb4_unicode_ci', `message` INT NOT NULL DEFAULT 0, `ccmessage` VARCHAR(16) COLLATE 'utf8mb4_unicode_ci', `ccaccess` INT NOT NULL DEFAULT 0, PRIMARY KEY (`auth`), CONSTRAINT `%sch_auth` FOREIGN KEY (`auth`) REFERENCES `%susers` (`auth`) ON UPDATE CASCADE ON DELETE CASCADE) ENGINE=INNODB;", "CREATE TABLE IF NOT EXISTS `%schat` (`auth` INT NOT NULL, `name` INT NOT NULL DEFAULT 0, `ccname` VARCHAR(128) COLLATE 'utf8mb4_unicode_ci', `message` INT NOT NULL DEFAULT 0, `ccmessage` VARCHAR(16) COLLATE 'utf8mb4_unicode_ci', `ccaccess` INT NOT NULL DEFAULT 0, PRIMARY KEY (`auth`), CONSTRAINT `%sch_auth` FOREIGN KEY (`auth`) REFERENCES `%susers` (`auth`) ON UPDATE CASCADE ON DELETE CASCADE) ENGINE=INNODB;",
gS_SQLPrefix, gS_SQLPrefix, gS_SQLPrefix); gS_SQLPrefix, gS_SQLPrefix, gS_SQLPrefix);
} }
else if (driver == Driver_pgsql)
{
FormatEx(sQuery, sizeof(sQuery),
"CREATE TABLE IF NOT EXISTS %schat (auth INT NOT NULL, name INT NOT NULL DEFAULT 0, ccname VARCHAR(128), message INT NOT NULL DEFAULT 0, ccmessage VARCHAR(16), ccaccess INT NOT NULL DEFAULT 0, PRIMARY KEY (auth), CONSTRAINT %sch_auth FOREIGN KEY (auth) REFERENCES %susers (auth) ON UPDATE CASCADE ON DELETE CASCADE);",
gS_SQLPrefix, gS_SQLPrefix, gS_SQLPrefix);
}
else else
{ {
FormatEx(sQuery, sizeof(sQuery), FormatEx(sQuery, sizeof(sQuery),
@ -177,18 +204,48 @@ public void SQL_CreateTables(Database hSQL, const char[] prefix, int driver)
//// shavit-rankings //// shavit-rankings
// //
FormatEx(sQuery, sizeof(sQuery), if (driver == Driver_mysql)
"CREATE TABLE IF NOT EXISTS `%smaptiers` (`map` VARCHAR(255) NOT NULL, `tier` INT NOT NULL DEFAULT 1, PRIMARY KEY (`map`)) %s;", {
gS_SQLPrefix, sOptionalINNODB); FormatEx(sQuery, sizeof(sQuery),
"CREATE TABLE IF NOT EXISTS `%smaptiers` (`map` VARCHAR(255) NOT NULL, `tier` INT NOT NULL DEFAULT 1, PRIMARY KEY (`map`)) %s;",
gS_SQLPrefix, sOptionalINNODB);
}
else if (driver == Driver_pgsql)
{
FormatEx(sQuery, sizeof(sQuery),
"CREATE TABLE IF NOT EXISTS %smaptiers (map VARCHAR(255) NOT NULL, tier INT NOT NULL DEFAULT 1, PRIMARY KEY (map));",
gS_SQLPrefix);
}
else
{
FormatEx(sQuery, sizeof(sQuery),
"CREATE TABLE IF NOT EXISTS `%smaptiers` (`map` VARCHAR(255) NOT NULL, `tier` INT NOT NULL DEFAULT 1, PRIMARY KEY (`map`)) %s;",
gS_SQLPrefix, sOptionalINNODB);
}
AddQueryLog(trans, sQuery); AddQueryLog(trans, sQuery);
// //
//// shavit-stats //// shavit-stats
// //
FormatEx(sQuery, sizeof(sQuery), if (driver == Driver_mysql)
"CREATE TABLE IF NOT EXISTS `%sstyleplaytime` (`auth` INT NOT NULL, `style` TINYINT NOT NULL, `playtime` FLOAT NOT NULL, PRIMARY KEY (`auth`, `style`));", {
gS_SQLPrefix); FormatEx(sQuery, sizeof(sQuery),
"CREATE TABLE IF NOT EXISTS `%sstyleplaytime` (`auth` INT NOT NULL, `style` TINYINT NOT NULL, `playtime` FLOAT NOT NULL, PRIMARY KEY (`auth`, `style`));",
gS_SQLPrefix);
}
else if (driver == Driver_pgsql)
{
FormatEx(sQuery, sizeof(sQuery),
"CREATE TABLE IF NOT EXISTS %sstyleplaytime (auth INT NOT NULL, style SMALLINT NOT NULL, playtime REAL NOT NULL, PRIMARY KEY (auth, style));",
gS_SQLPrefix);
}
else
{
FormatEx(sQuery, sizeof(sQuery),
"CREATE TABLE IF NOT EXISTS `%sstyleplaytime` (`auth` INT NOT NULL, `style` TINYINT NOT NULL, `playtime` FLOAT NOT NULL, PRIMARY KEY (`auth`, `style`));",
gS_SQLPrefix);
}
AddQueryLog(trans, sQuery); AddQueryLog(trans, sQuery);
// //
@ -201,6 +258,12 @@ public void SQL_CreateTables(Database hSQL, const char[] prefix, int driver)
"CREATE TABLE IF NOT EXISTS `%splayertimes` (`id` INT NOT NULL AUTO_INCREMENT, `style` TINYINT NOT NULL DEFAULT 0, `track` TINYINT NOT NULL DEFAULT 0, `time` FLOAT NOT NULL, `auth` INT NOT NULL, `map` VARCHAR(255) NOT NULL, `points` FLOAT NOT NULL DEFAULT 0, `jumps` INT, `date` INT, `strafes` INT, `sync` FLOAT, `perfs` FLOAT DEFAULT 0, `completions` SMALLINT DEFAULT 1, PRIMARY KEY (`id`), INDEX `map` (`map`, `style`, `track`, `time`), INDEX `auth` (`auth`, `date`, `points`), INDEX `time` (`time`), INDEX `map2` (`map`), CONSTRAINT `%spt_auth` FOREIGN KEY (`auth`) REFERENCES `%susers` (`auth`) ON UPDATE RESTRICT ON DELETE RESTRICT) ENGINE=INNODB;", "CREATE TABLE IF NOT EXISTS `%splayertimes` (`id` INT NOT NULL AUTO_INCREMENT, `style` TINYINT NOT NULL DEFAULT 0, `track` TINYINT NOT NULL DEFAULT 0, `time` FLOAT NOT NULL, `auth` INT NOT NULL, `map` VARCHAR(255) NOT NULL, `points` FLOAT NOT NULL DEFAULT 0, `jumps` INT, `date` INT, `strafes` INT, `sync` FLOAT, `perfs` FLOAT DEFAULT 0, `completions` SMALLINT DEFAULT 1, PRIMARY KEY (`id`), INDEX `map` (`map`, `style`, `track`, `time`), INDEX `auth` (`auth`, `date`, `points`), INDEX `time` (`time`), INDEX `map2` (`map`), CONSTRAINT `%spt_auth` FOREIGN KEY (`auth`) REFERENCES `%susers` (`auth`) ON UPDATE RESTRICT ON DELETE RESTRICT) ENGINE=INNODB;",
gS_SQLPrefix, gS_SQLPrefix, gS_SQLPrefix); gS_SQLPrefix, gS_SQLPrefix, gS_SQLPrefix);
} }
else if (driver == Driver_pgsql)
{
FormatEx(sQuery, sizeof(sQuery),
"CREATE TABLE IF NOT EXISTS %splayertimes (id SERIAL PRIMARY KEY, style SMALLINT NOT NULL DEFAULT 0, track SMALLINT NOT NULL DEFAULT 0, time REAL NOT NULL, auth INT NOT NULL, map VARCHAR(255) NOT NULL, points REAL NOT NULL DEFAULT 0, jumps INT, date INT, strafes INT, sync REAL, perfs REAL DEFAULT 0, completions SMALLINT DEFAULT 1, CONSTRAINT %spt_auth FOREIGN KEY (auth) REFERENCES %susers (auth) ON UPDATE RESTRICT ON DELETE RESTRICT);",
gS_SQLPrefix, gS_SQLPrefix, gS_SQLPrefix);
}
else else
{ {
// id style track time auth map points exact_time_int // id style track time auth map points exact_time_int
@ -212,14 +275,44 @@ public void SQL_CreateTables(Database hSQL, const char[] prefix, int driver)
AddQueryLog(trans, sQuery); AddQueryLog(trans, sQuery);
FormatEx(sQuery, sizeof(sQuery), if (driver == Driver_mysql)
"CREATE TABLE IF NOT EXISTS `%sstagetimeswr` (`style` TINYINT NOT NULL, `track` TINYINT NOT NULL DEFAULT 0, `map` VARCHAR(255) NOT NULL, `stage` TINYINT NOT NULL, `auth` INT NOT NULL, `time` FLOAT NOT NULL, PRIMARY KEY (`style`, `track`, `map`, `stage`)) %s;", {
gS_SQLPrefix, sOptionalINNODB); FormatEx(sQuery, sizeof(sQuery),
"CREATE TABLE IF NOT EXISTS `%sstagetimeswr` (`style` TINYINT NOT NULL, `track` TINYINT NOT NULL DEFAULT 0, `map` VARCHAR(255) NOT NULL, `stage` TINYINT NOT NULL, `auth` INT NOT NULL, `time` FLOAT NOT NULL, PRIMARY KEY (`style`, `track`, `map`, `stage`)) %s;",
gS_SQLPrefix, sOptionalINNODB);
}
else if (driver == Driver_pgsql)
{
FormatEx(sQuery, sizeof(sQuery),
"CREATE TABLE IF NOT EXISTS %sstagetimeswr (style SMALLINT NOT NULL, track SMALLINT NOT NULL DEFAULT 0, map VARCHAR(255) NOT NULL, stage SMALLINT NOT NULL, auth INT NOT NULL, time REAL NOT NULL, PRIMARY KEY (style, track, map, stage));",
gS_SQLPrefix);
}
else
{
FormatEx(sQuery, sizeof(sQuery),
"CREATE TABLE IF NOT EXISTS `%sstagetimeswr` (`style` TINYINT NOT NULL, `track` TINYINT NOT NULL DEFAULT 0, `map` VARCHAR(255) NOT NULL, `stage` TINYINT NOT NULL, `auth` INT NOT NULL, `time` FLOAT NOT NULL, PRIMARY KEY (`style`, `track`, `map`, `stage`)) %s;",
gS_SQLPrefix, sOptionalINNODB);
}
AddQueryLog(trans, sQuery); AddQueryLog(trans, sQuery);
FormatEx(sQuery, sizeof(sQuery), if (driver == Driver_mysql)
"CREATE TABLE IF NOT EXISTS `%sstagetimespb` (`style` TINYINT NOT NULL, `track` TINYINT NOT NULL DEFAULT 0, `map` VARCHAR(255) NOT NULL, `stage` TINYINT NOT NULL, `auth` INT NOT NULL, `time` FLOAT NOT NULL, PRIMARY KEY (`style`, `track`, `auth`, `map`, `stage`)) %s;", {
gS_SQLPrefix, sOptionalINNODB); FormatEx(sQuery, sizeof(sQuery),
"CREATE TABLE IF NOT EXISTS `%sstagetimespb` (`style` TINYINT NOT NULL, `track` TINYINT NOT NULL DEFAULT 0, `map` VARCHAR(255) NOT NULL, `stage` TINYINT NOT NULL, `auth` INT NOT NULL, `time` FLOAT NOT NULL, PRIMARY KEY (`style`, `track`, `auth`, `map`, `stage`)) %s;",
gS_SQLPrefix, sOptionalINNODB);
}
else if (driver == Driver_pgsql)
{
FormatEx(sQuery, sizeof(sQuery),
"CREATE TABLE IF NOT EXISTS %sstagetimespb (style SMALLINT NOT NULL, track SMALLINT NOT NULL DEFAULT 0, map VARCHAR(255) NOT NULL, stage SMALLINT NOT NULL, auth INT NOT NULL, time REAL NOT NULL, PRIMARY KEY (style, track, auth, map, stage));",
gS_SQLPrefix);
}
else
{
FormatEx(sQuery, sizeof(sQuery),
"CREATE TABLE IF NOT EXISTS `%sstagetimespb` (`style` TINYINT NOT NULL, `track` TINYINT NOT NULL DEFAULT 0, `map` VARCHAR(255) NOT NULL, `stage` TINYINT NOT NULL, `auth` INT NOT NULL, `time` FLOAT NOT NULL, PRIMARY KEY (`style`, `track`, `auth`, `map`, `stage`)) %s;",
gS_SQLPrefix, sOptionalINNODB);
}
AddQueryLog(trans, sQuery); AddQueryLog(trans, sQuery);
if (driver == Driver_sqlite) if (driver == Driver_sqlite)
@ -230,16 +323,44 @@ public void SQL_CreateTables(Database hSQL, const char[] prefix, int driver)
AddQueryLog(trans, sQuery); AddQueryLog(trans, sQuery);
} }
FormatEx(sQuery, sizeof(sQuery), if (driver == Driver_mysql)
"%s %swrs_min AS SELECT MIN(time) time, map, track, style FROM %splayertimes GROUP BY map, track, style;", {
driver == Driver_sqlite ? "CREATE VIEW IF NOT EXISTS" : "CREATE OR REPLACE VIEW", FormatEx(sQuery, sizeof(sQuery),
gS_SQLPrefix, gS_SQLPrefix); "CREATE OR REPLACE VIEW %swrs_min AS SELECT MIN(time) time, map, track, style FROM %splayertimes GROUP BY map, track, style;",
gS_SQLPrefix, gS_SQLPrefix);
}
else if (driver == Driver_pgsql)
{
FormatEx(sQuery, sizeof(sQuery),
"CREATE OR REPLACE VIEW %swrs_min AS SELECT MIN(time) time, map, track, style FROM %splayertimes GROUP BY map, track, style;",
gS_SQLPrefix, gS_SQLPrefix);
}
else
{
FormatEx(sQuery, sizeof(sQuery),
"CREATE VIEW IF NOT EXISTS %swrs_min AS SELECT MIN(time) time, map, track, style FROM %splayertimes GROUP BY map, track, style;",
gS_SQLPrefix, gS_SQLPrefix);
}
AddQueryLog(trans, sQuery); AddQueryLog(trans, sQuery);
FormatEx(sQuery, sizeof(sQuery), if (driver == Driver_mysql)
"%s %swrs AS SELECT a.* FROM %splayertimes a JOIN %swrs_min b ON a.time = b.time AND a.map = b.map AND a.track = b.track AND a.style = b.style;", {
driver == Driver_sqlite ? "CREATE VIEW IF NOT EXISTS" : "CREATE OR REPLACE VIEW", FormatEx(sQuery, sizeof(sQuery),
gS_SQLPrefix, gS_SQLPrefix, gS_SQLPrefix); "CREATE OR REPLACE VIEW %swrs AS SELECT a.* FROM %splayertimes a JOIN %swrs_min b ON a.time = b.time AND a.map = b.map AND a.track = b.track AND a.style = b.style;",
gS_SQLPrefix, gS_SQLPrefix, gS_SQLPrefix);
}
else if (driver == Driver_pgsql)
{
FormatEx(sQuery, sizeof(sQuery),
"CREATE OR REPLACE VIEW %swrs AS SELECT a.* FROM %splayertimes a JOIN %swrs_min b ON a.time = b.time AND a.map = b.map AND a.track = b.track AND a.style = b.style;",
gS_SQLPrefix, gS_SQLPrefix, gS_SQLPrefix);
}
else
{
FormatEx(sQuery, sizeof(sQuery),
"CREATE VIEW IF NOT EXISTS %swrs AS SELECT a.* FROM %splayertimes a JOIN %swrs_min b ON a.time = b.time AND a.map = b.map AND a.track = b.track AND a.style = b.style;",
gS_SQLPrefix, gS_SQLPrefix, gS_SQLPrefix);
}
AddQueryLog(trans, sQuery); AddQueryLog(trans, sQuery);
// //
@ -253,6 +374,13 @@ public void SQL_CreateTables(Database hSQL, const char[] prefix, int driver)
gS_SQLPrefix, sOptionalINNODB); gS_SQLPrefix, sOptionalINNODB);
AddQueryLog(trans, sQuery); AddQueryLog(trans, sQuery);
} }
else if (driver == Driver_pgsql)
{
FormatEx(sQuery, sizeof(sQuery),
"CREATE TABLE IF NOT EXISTS %smapzones (id SERIAL PRIMARY KEY, map VARCHAR(255) NOT NULL, type INT, corner1_x REAL, corner1_y REAL, corner1_z REAL, corner2_x REAL, corner2_y REAL, corner2_z REAL, destination_x REAL NOT NULL DEFAULT 0, destination_y REAL NOT NULL DEFAULT 0, destination_z REAL NOT NULL DEFAULT 0, track INT NOT NULL DEFAULT 0, flags INT NOT NULL DEFAULT 0, data INT NOT NULL DEFAULT 0, form SMALLINT, target VARCHAR(63));",
gS_SQLPrefix);
AddQueryLog(trans, sQuery);
}
else else
{ {
FormatEx(sQuery, sizeof(sQuery), FormatEx(sQuery, sizeof(sQuery),
@ -262,11 +390,48 @@ public void SQL_CreateTables(Database hSQL, const char[] prefix, int driver)
strcopy(SQLiteMapzonesQuery, sizeof(SQLiteMapzonesQuery), sQuery); strcopy(SQLiteMapzonesQuery, sizeof(SQLiteMapzonesQuery), sQuery);
} }
FormatEx(sQuery, sizeof(sQuery), if (driver == Driver_mysql)
"CREATE TABLE IF NOT EXISTS `%sstartpositions` (`auth` INTEGER NOT NULL, `track` TINYINT NOT NULL, `map` VARCHAR(255) NOT NULL, `pos_x` FLOAT, `pos_y` FLOAT, `pos_z` FLOAT, `ang_x` FLOAT, `ang_y` FLOAT, `ang_z` FLOAT, `angles_only` BOOL, PRIMARY KEY (`auth`, `track`, `map`)) %s;", {
gS_SQLPrefix, sOptionalINNODB); FormatEx(sQuery, sizeof(sQuery),
"CREATE TABLE IF NOT EXISTS `%sstartpositions` (`auth` INTEGER NOT NULL, `track` TINYINT NOT NULL, `map` VARCHAR(255) NOT NULL, `pos_x` FLOAT, `pos_y` FLOAT, `pos_z` FLOAT, `ang_x` FLOAT, `ang_y` FLOAT, `ang_z` FLOAT, `angles_only` BOOL, PRIMARY KEY (`auth`, `track`, `map`)) %s;",
gS_SQLPrefix, sOptionalINNODB);
}
else if (driver == Driver_pgsql)
{
FormatEx(sQuery, sizeof(sQuery),
"CREATE TABLE IF NOT EXISTS %sstartpositions (auth INTEGER NOT NULL, track SMALLINT NOT NULL, map VARCHAR(255) NOT NULL, pos_x REAL, pos_y REAL, pos_z REAL, ang_x REAL, ang_y REAL, ang_z REAL, angles_only BOOLEAN, PRIMARY KEY (auth, track, map));",
gS_SQLPrefix);
}
else
{
FormatEx(sQuery, sizeof(sQuery),
"CREATE TABLE IF NOT EXISTS `%sstartpositions` (`auth` INTEGER NOT NULL, `track` TINYINT NOT NULL, `map` VARCHAR(255) NOT NULL, `pos_x` FLOAT, `pos_y` FLOAT, `pos_z` FLOAT, `ang_x` FLOAT, `ang_y` FLOAT, `ang_z` FLOAT, `angles_only` BOOL, PRIMARY KEY (`auth`, `track`, `map`)) %s;",
gS_SQLPrefix, sOptionalINNODB);
}
AddQueryLog(trans, sQuery); AddQueryLog(trans, sQuery);
// PostgreSQL indexes need to be created separately
if (driver == Driver_pgsql)
{
FormatEx(sQuery, sizeof(sQuery), "CREATE INDEX IF NOT EXISTS %susers_points_idx ON %susers (points);", gS_SQLPrefix, gS_SQLPrefix);
AddQueryLog(trans, sQuery);
FormatEx(sQuery, sizeof(sQuery), "CREATE INDEX IF NOT EXISTS %susers_lastlogin_idx ON %susers (lastlogin);", gS_SQLPrefix, gS_SQLPrefix);
AddQueryLog(trans, sQuery);
FormatEx(sQuery, sizeof(sQuery), "CREATE INDEX IF NOT EXISTS %splayertimes_map_idx ON %splayertimes (map, style, track, time);", gS_SQLPrefix, gS_SQLPrefix);
AddQueryLog(trans, sQuery);
FormatEx(sQuery, sizeof(sQuery), "CREATE INDEX IF NOT EXISTS %splayertimes_auth_idx ON %splayertimes (auth, date, points);", gS_SQLPrefix, gS_SQLPrefix);
AddQueryLog(trans, sQuery);
FormatEx(sQuery, sizeof(sQuery), "CREATE INDEX IF NOT EXISTS %splayertimes_time_idx ON %splayertimes (time);", gS_SQLPrefix, gS_SQLPrefix);
AddQueryLog(trans, sQuery);
FormatEx(sQuery, sizeof(sQuery), "CREATE INDEX IF NOT EXISTS %splayertimes_map2_idx ON %splayertimes (map);", gS_SQLPrefix, gS_SQLPrefix);
AddQueryLog(trans, sQuery);
}
hSQL.Execute(trans, Trans_CreateTables_Success, Trans_CreateTables_Error, 0, DBPrio_High); hSQL.Execute(trans, Trans_CreateTables_Success, Trans_CreateTables_Error, 0, DBPrio_High);
} }
@ -381,42 +546,108 @@ void ApplyMigration(int migration)
void ApplyMigration_LastLoginIndex() void ApplyMigration_LastLoginIndex()
{ {
char sQuery[128]; char sQuery[128];
FormatEx(sQuery, 128, "ALTER TABLE `%susers` ADD INDEX `lastlogin` (`lastlogin`);", gS_SQLPrefix); if (gI_Driver == Driver_mysql)
{
FormatEx(sQuery, 128, "ALTER TABLE `%susers` ADD INDEX `lastlogin` (`lastlogin`);", gS_SQLPrefix);
}
else if (gI_Driver == Driver_pgsql)
{
FormatEx(sQuery, 128, "CREATE INDEX lastlogin ON %susers (lastlogin);", gS_SQLPrefix);
}
else // SQLite
{
FormatEx(sQuery, 128, "CREATE INDEX lastlogin ON `%susers` (`lastlogin`);", gS_SQLPrefix);
}
QueryLog(gH_SQL, SQL_TableMigrationSingleQuery_Callback, sQuery, Migration_LastLoginIndex, DBPrio_High); QueryLog(gH_SQL, SQL_TableMigrationSingleQuery_Callback, sQuery, Migration_LastLoginIndex, DBPrio_High);
} }
void ApplyMigration_RemoveCountry() void ApplyMigration_RemoveCountry()
{ {
char sQuery[128]; char sQuery[128];
FormatEx(sQuery, 128, "ALTER TABLE `%susers` DROP COLUMN `country`;", gS_SQLPrefix); if (gI_Driver == Driver_mysql)
{
FormatEx(sQuery, 128, "ALTER TABLE `%susers` DROP COLUMN `country`;", gS_SQLPrefix);
}
else if (gI_Driver == Driver_pgsql)
{
FormatEx(sQuery, 128, "ALTER TABLE %susers DROP COLUMN country;", gS_SQLPrefix);
}
else // SQLite
{
FormatEx(sQuery, 128, "ALTER TABLE `%susers` DROP COLUMN `country`;", gS_SQLPrefix);
}
QueryLog(gH_SQL, SQL_TableMigrationSingleQuery_Callback, sQuery, Migration_RemoveCountry, DBPrio_High); QueryLog(gH_SQL, SQL_TableMigrationSingleQuery_Callback, sQuery, Migration_RemoveCountry, DBPrio_High);
} }
void ApplyMigration_PlayertimesDateToInt() void ApplyMigration_PlayertimesDateToInt()
{ {
char sQuery[128]; char sQuery[128];
FormatEx(sQuery, 128, "ALTER TABLE `%splayertimes` CHANGE COLUMN `date` `date` INT;", gS_SQLPrefix); if (gI_Driver == Driver_mysql)
{
FormatEx(sQuery, 128, "ALTER TABLE `%splayertimes` CHANGE COLUMN `date` `date` INT;", gS_SQLPrefix);
}
else if (gI_Driver == Driver_pgsql)
{
FormatEx(sQuery, 128, "ALTER TABLE %splayertimes ALTER COLUMN date TYPE INT;", gS_SQLPrefix);
}
else // SQLite - doesn't support ALTER COLUMN type changes
{
FormatEx(sQuery, 128, "-- SQLite doesn't support ALTER COLUMN type changes");
}
QueryLog(gH_SQL, SQL_TableMigrationSingleQuery_Callback, sQuery, Migration_PlayertimesDateToInt, DBPrio_High); QueryLog(gH_SQL, SQL_TableMigrationSingleQuery_Callback, sQuery, Migration_PlayertimesDateToInt, DBPrio_High);
} }
void ApplyMigration_AddZonesFlagsAndData() void ApplyMigration_AddZonesFlagsAndData()
{ {
char sQuery[192]; char sQuery[192];
FormatEx(sQuery, 192, "ALTER TABLE `%smapzones` ADD COLUMN `flags` INT NULL AFTER `track`, ADD COLUMN `data` INT NULL AFTER `flags`;", gS_SQLPrefix); if (gI_Driver == Driver_mysql)
{
FormatEx(sQuery, 192, "ALTER TABLE `%smapzones` ADD COLUMN `flags` INT NULL AFTER `track`, ADD COLUMN `data` INT NULL AFTER `flags`;", gS_SQLPrefix);
}
else if (gI_Driver == Driver_pgsql)
{
FormatEx(sQuery, 192, "ALTER TABLE %smapzones ADD COLUMN flags INT NULL, ADD COLUMN data INT NULL;", gS_SQLPrefix);
}
else // SQLite
{
FormatEx(sQuery, 192, "ALTER TABLE `%smapzones` ADD COLUMN `flags` INT NULL, ADD COLUMN `data` INT NULL;", gS_SQLPrefix);
}
QueryLog(gH_SQL, SQL_TableMigrationSingleQuery_Callback, sQuery, Migration_AddZonesFlagsAndData, DBPrio_High); QueryLog(gH_SQL, SQL_TableMigrationSingleQuery_Callback, sQuery, Migration_AddZonesFlagsAndData, DBPrio_High);
} }
void ApplyMigration_AddPlayertimesCompletions() void ApplyMigration_AddPlayertimesCompletions()
{ {
char sQuery[192]; char sQuery[192];
FormatEx(sQuery, 192, "ALTER TABLE `%splayertimes` ADD COLUMN `completions` SMALLINT DEFAULT 1 AFTER `perfs`;", gS_SQLPrefix); if (gI_Driver == Driver_mysql)
{
FormatEx(sQuery, 192, "ALTER TABLE `%splayertimes` ADD COLUMN `completions` SMALLINT DEFAULT 1 AFTER `perfs`;", gS_SQLPrefix);
}
else if (gI_Driver == Driver_pgsql)
{
FormatEx(sQuery, 192, "ALTER TABLE %splayertimes ADD COLUMN completions SMALLINT DEFAULT 1;", gS_SQLPrefix);
}
else // SQLite
{
FormatEx(sQuery, 192, "ALTER TABLE `%splayertimes` ADD COLUMN `completions` SMALLINT DEFAULT 1;", gS_SQLPrefix);
}
QueryLog(gH_SQL, SQL_TableMigrationSingleQuery_Callback, sQuery, Migration_AddPlayertimesCompletions, DBPrio_High); QueryLog(gH_SQL, SQL_TableMigrationSingleQuery_Callback, sQuery, Migration_AddPlayertimesCompletions, DBPrio_High);
} }
void ApplyMigration_AddCustomChatAccess() void ApplyMigration_AddCustomChatAccess()
{ {
char sQuery[192]; char sQuery[192];
FormatEx(sQuery, 192, "ALTER TABLE `%schat` ADD COLUMN `ccaccess` INT NOT NULL DEFAULT 0 %s;", gS_SQLPrefix, (gI_Driver == Driver_mysql) ? "AFTER `ccmessage`" : ""); if (gI_Driver == Driver_mysql)
{
FormatEx(sQuery, 192, "ALTER TABLE `%schat` ADD COLUMN `ccaccess` INT NOT NULL DEFAULT 0 AFTER `ccmessage`;", gS_SQLPrefix);
}
else if (gI_Driver == Driver_pgsql)
{
FormatEx(sQuery, 192, "ALTER TABLE %schat ADD COLUMN ccaccess INT NOT NULL DEFAULT 0;", gS_SQLPrefix);
}
else // SQLite
{
FormatEx(sQuery, 192, "ALTER TABLE `%schat` ADD COLUMN `ccaccess` INT NOT NULL DEFAULT 0;", gS_SQLPrefix);
}
QueryLog(gH_SQL, SQL_TableMigrationSingleQuery_Callback, sQuery, Migration_AddCustomChatAccess, DBPrio_High); QueryLog(gH_SQL, SQL_TableMigrationSingleQuery_Callback, sQuery, Migration_AddCustomChatAccess, DBPrio_High);
} }
@ -434,7 +665,18 @@ void ApplyMigration_AddPlayertimesExactTimeInt()
void ApplyMigration_FixOldCompletionCounts() void ApplyMigration_FixOldCompletionCounts()
{ {
char sQuery[192]; char sQuery[192];
FormatEx(sQuery, 192, "UPDATE `%splayertimes` SET completions = completions - 1 WHERE completions > 1;", gS_SQLPrefix); if (gI_Driver == Driver_mysql)
{
FormatEx(sQuery, 192, "UPDATE `%splayertimes` SET completions = completions - 1 WHERE completions > 1;", gS_SQLPrefix);
}
else if (gI_Driver == Driver_pgsql)
{
FormatEx(sQuery, 192, "UPDATE %splayertimes SET completions = completions - 1 WHERE completions > 1;", gS_SQLPrefix);
}
else // SQLite
{
FormatEx(sQuery, 192, "UPDATE `%splayertimes` SET completions = completions - 1 WHERE completions > 1;", gS_SQLPrefix);
}
QueryLog(gH_SQL, SQL_TableMigrationSingleQuery_Callback, sQuery, Migration_FixOldCompletionCounts, DBPrio_High); QueryLog(gH_SQL, SQL_TableMigrationSingleQuery_Callback, sQuery, Migration_FixOldCompletionCounts, DBPrio_High);
} }
@ -453,14 +695,36 @@ void ApplyMigration_AddPrebuiltToMapZonesTable()
void ApplyMigration_AddPlaytime() void ApplyMigration_AddPlaytime()
{ {
char sQuery[192]; char sQuery[192];
FormatEx(sQuery, 192, "ALTER TABLE `%susers` MODIFY COLUMN `playtime` FLOAT NOT NULL DEFAULT 0;", gS_SQLPrefix); if (gI_Driver == Driver_mysql)
{
FormatEx(sQuery, 192, "ALTER TABLE `%susers` MODIFY COLUMN `playtime` FLOAT NOT NULL DEFAULT 0;", gS_SQLPrefix);
}
else if (gI_Driver == Driver_pgsql)
{
FormatEx(sQuery, 192, "ALTER TABLE %susers ALTER COLUMN playtime TYPE REAL USING playtime::REAL;", gS_SQLPrefix);
}
else // SQLite
{
FormatEx(sQuery, 192, "-- SQLite doesn't support ALTER COLUMN type changes");
}
QueryLog(gH_SQL, SQL_Migration_AddPlaytime2222222_Callback, sQuery, Migration_AddPlaytime, DBPrio_High); QueryLog(gH_SQL, SQL_Migration_AddPlaytime2222222_Callback, sQuery, Migration_AddPlaytime, DBPrio_High);
} }
public void SQL_Migration_AddPlaytime2222222_Callback(Database db, DBResultSet results, const char[] error, any data) public void SQL_Migration_AddPlaytime2222222_Callback(Database db, DBResultSet results, const char[] error, any data)
{ {
char sQuery[192]; char sQuery[192];
FormatEx(sQuery, 192, "ALTER TABLE `%susers` ADD COLUMN `playtime` FLOAT NOT NULL DEFAULT 0 %s;", gS_SQLPrefix, (gI_Driver == Driver_mysql) ? "AFTER `points`" : ""); if (gI_Driver == Driver_mysql)
{
FormatEx(sQuery, 192, "ALTER TABLE `%susers` ADD COLUMN `playtime` FLOAT NOT NULL DEFAULT 0 AFTER `points`;", gS_SQLPrefix);
}
else if (gI_Driver == Driver_pgsql)
{
FormatEx(sQuery, 192, "ALTER TABLE %susers ADD COLUMN playtime REAL NOT NULL DEFAULT 0;", gS_SQLPrefix);
}
else // SQLite
{
FormatEx(sQuery, 192, "ALTER TABLE `%susers` ADD COLUMN `playtime` REAL NOT NULL DEFAULT 0;", gS_SQLPrefix);
}
QueryLog(gH_SQL, SQL_TableMigrationSingleQuery_Callback, sQuery, Migration_AddPlaytime, DBPrio_High); QueryLog(gH_SQL, SQL_TableMigrationSingleQuery_Callback, sQuery, Migration_AddPlaytime, DBPrio_High);
} }
@ -485,7 +749,18 @@ void ApplyMigration_AddPlayertimesPointsCalcedFrom()
void ApplyMigration_RemovePlayertimesPointsCalcedFrom() void ApplyMigration_RemovePlayertimesPointsCalcedFrom()
{ {
char sQuery[192]; char sQuery[192];
FormatEx(sQuery, 192, "ALTER TABLE `%splayertimes` DROP COLUMN `points_calced_from`;", gS_SQLPrefix); if (gI_Driver == Driver_mysql)
{
FormatEx(sQuery, 192, "ALTER TABLE `%splayertimes` DROP COLUMN `points_calced_from`;", gS_SQLPrefix);
}
else if (gI_Driver == Driver_pgsql)
{
FormatEx(sQuery, 192, "ALTER TABLE %splayertimes DROP COLUMN points_calced_from;", gS_SQLPrefix);
}
else // SQLite
{
FormatEx(sQuery, 192, "ALTER TABLE `%splayertimes` DROP COLUMN `points_calced_from`;", gS_SQLPrefix);
}
QueryLog(gH_SQL, SQL_TableMigrationSingleQuery_Callback, sQuery, Migration_RemovePlayertimesPointsCalcedFrom, DBPrio_High); QueryLog(gH_SQL, SQL_TableMigrationSingleQuery_Callback, sQuery, Migration_RemovePlayertimesPointsCalcedFrom, DBPrio_High);
} }
@ -517,14 +792,36 @@ void ApplyMigration_NormalizeMapzonePoints() // TODO: test with sqlite lol
void ApplyMigration_AddMapzonesForm() void ApplyMigration_AddMapzonesForm()
{ {
char sQuery[192]; char sQuery[192];
FormatEx(sQuery, sizeof(sQuery), "ALTER TABLE `%smapzones` ADD COLUMN `form` TINYINT;", gS_SQLPrefix); if (gI_Driver == Driver_mysql)
{
FormatEx(sQuery, sizeof(sQuery), "ALTER TABLE `%smapzones` ADD COLUMN `form` TINYINT;", gS_SQLPrefix);
}
else if (gI_Driver == Driver_pgsql)
{
FormatEx(sQuery, sizeof(sQuery), "ALTER TABLE %smapzones ADD COLUMN form SMALLINT;", gS_SQLPrefix);
}
else // SQLite
{
FormatEx(sQuery, sizeof(sQuery), "ALTER TABLE `%smapzones` ADD COLUMN `form` TINYINT;", gS_SQLPrefix);
}
QueryLog(gH_SQL, SQL_TableMigrationSingleQuery_Callback, sQuery, Migration_AddMapzonesForm, DBPrio_High); QueryLog(gH_SQL, SQL_TableMigrationSingleQuery_Callback, sQuery, Migration_AddMapzonesForm, DBPrio_High);
} }
void ApplyMigration_AddMapzonesTarget() void ApplyMigration_AddMapzonesTarget()
{ {
char sQuery[192]; char sQuery[192];
FormatEx(sQuery, sizeof(sQuery), "ALTER TABLE `%smapzones` ADD COLUMN `target` VARCHAR(63);", gS_SQLPrefix); if (gI_Driver == Driver_mysql)
{
FormatEx(sQuery, sizeof(sQuery), "ALTER TABLE `%smapzones` ADD COLUMN `target` VARCHAR(63);", gS_SQLPrefix);
}
else if (gI_Driver == Driver_pgsql)
{
FormatEx(sQuery, sizeof(sQuery), "ALTER TABLE %smapzones ADD COLUMN target VARCHAR(63);", gS_SQLPrefix);
}
else // SQLite
{
FormatEx(sQuery, sizeof(sQuery), "ALTER TABLE `%smapzones` ADD COLUMN `target` VARCHAR(63);", gS_SQLPrefix);
}
QueryLog(gH_SQL, SQL_TableMigrationSingleQuery_Callback, sQuery, Migration_AddMapzonesTarget, DBPrio_High); QueryLog(gH_SQL, SQL_TableMigrationSingleQuery_Callback, sQuery, Migration_AddMapzonesTarget, DBPrio_High);
} }
@ -695,14 +992,36 @@ public void Trans_FixSQLiteMapzonesROWID_Error(Database db, any data, int numQue
void ApplyMigration_AddUsersFirstLogin() void ApplyMigration_AddUsersFirstLogin()
{ {
char sQuery[256]; char sQuery[256];
FormatEx(sQuery, sizeof(sQuery), "ALTER TABLE %susers ADD `firstlogin` INT NOT NULL DEFAULT -1 %s;", gS_SQLPrefix, (gI_Driver == Driver_mysql) ? "AFTER `lastlogin`" : ""); if (gI_Driver == Driver_mysql)
{
FormatEx(sQuery, sizeof(sQuery), "ALTER TABLE %susers ADD `firstlogin` INT NOT NULL DEFAULT -1 AFTER `lastlogin`;", gS_SQLPrefix);
}
else if (gI_Driver == Driver_pgsql)
{
FormatEx(sQuery, sizeof(sQuery), "ALTER TABLE %susers ADD firstlogin INT NOT NULL DEFAULT -1;", gS_SQLPrefix);
}
else // SQLite
{
FormatEx(sQuery, sizeof(sQuery), "ALTER TABLE %susers ADD `firstlogin` INT NOT NULL DEFAULT -1;", gS_SQLPrefix);
}
QueryLog(gH_SQL, ApplyMigration_AddUsersFirstLogin2222222_Callback, sQuery, Migration_AddUsersFirstLogin, DBPrio_High); QueryLog(gH_SQL, ApplyMigration_AddUsersFirstLogin2222222_Callback, sQuery, Migration_AddUsersFirstLogin, DBPrio_High);
} }
public void ApplyMigration_AddUsersFirstLogin2222222_Callback(Database db, DBResultSet results, const char[] error, any data) public void ApplyMigration_AddUsersFirstLogin2222222_Callback(Database db, DBResultSet results, const char[] error, any data)
{ {
char sQuery[256]; char sQuery[256];
FormatEx(sQuery, sizeof(sQuery), "UPDATE %susers SET firstlogin = lastlogin WHERE lastlogin > 1188518400;", gS_SQLPrefix); if (gI_Driver == Driver_mysql)
{
FormatEx(sQuery, sizeof(sQuery), "UPDATE `%susers` SET firstlogin = lastlogin WHERE lastlogin > 1188518400;", gS_SQLPrefix);
}
else if (gI_Driver == Driver_pgsql)
{
FormatEx(sQuery, sizeof(sQuery), "UPDATE %susers SET firstlogin = lastlogin WHERE lastlogin > 1188518400;", gS_SQLPrefix);
}
else // SQLite
{
FormatEx(sQuery, sizeof(sQuery), "UPDATE `%susers` SET firstlogin = lastlogin WHERE lastlogin > 1188518400;", gS_SQLPrefix);
}
QueryLog(gH_SQL, SQL_TableMigrationSingleQuery_Callback, sQuery, Migration_AddUsersFirstLogin, DBPrio_High); QueryLog(gH_SQL, SQL_TableMigrationSingleQuery_Callback, sQuery, Migration_AddUsersFirstLogin, DBPrio_High);
} }
@ -738,7 +1057,34 @@ public void ApplyMigration_MoreFirstLoginStuff()
); );
AddQueryLog(trans, query); AddQueryLog(trans, query);
} }
else // sqlite & postgresql use the same syntax here else if (gI_Driver == Driver_pgsql)
{
FormatEx(query, sizeof(query),
"UPDATE %susers SET firstlogin = pt.min_date::INT \
FROM ( \
SELECT auth, MIN(FLOOR(date - time))::INT as min_date \
FROM %splayertimes \
WHERE date > 1188518400 \
GROUP BY auth \
) as pt \
WHERE %susers.auth = pt.auth AND firstlogin <= 0;",
gS_SQLPrefix, gS_SQLPrefix, gS_SQLPrefix
);
AddQueryLog(trans, query);
FormatEx(query, sizeof(query),
"UPDATE %susers SET firstlogin = LEAST(firstlogin, pt.min_date::INT) \
FROM ( \
SELECT auth, MIN(FLOOR(date - time))::INT as min_date \
FROM %splayertimes \
WHERE date > 1188518400 \
GROUP BY auth \
) as pt \
WHERE %susers.auth = pt.auth AND firstlogin > 0;",
gS_SQLPrefix, gS_SQLPrefix, gS_SQLPrefix
);
AddQueryLog(trans, query);
}
else // sqlite
{ {
FormatEx(query, sizeof(query), FormatEx(query, sizeof(query),
"UPDATE %susers SET firstlogin = pt.min_date \ "UPDATE %susers SET firstlogin = pt.min_date \
@ -923,11 +1269,33 @@ void ApplyMigration_ConvertIPAddresses(bool index = true)
if (index) if (index)
{ {
FormatEx(sQuery, 128, "ALTER TABLE `%susers` ADD INDEX `ip` (`ip`);", gS_SQLPrefix); if (gI_Driver == Driver_mysql)
{
FormatEx(sQuery, 128, "ALTER TABLE `%susers` ADD INDEX `ip` (`ip`);", gS_SQLPrefix);
}
else if (gI_Driver == Driver_pgsql)
{
FormatEx(sQuery, 128, "CREATE INDEX ip ON %susers (ip);", gS_SQLPrefix);
}
else // SQLite
{
FormatEx(sQuery, 128, "CREATE INDEX ip ON `%susers` (`ip`);", gS_SQLPrefix);
}
QueryLog(gH_SQL, SQL_TableMigrationIndexing_Callback, sQuery, 0, DBPrio_High); QueryLog(gH_SQL, SQL_TableMigrationIndexing_Callback, sQuery, 0, DBPrio_High);
} }
FormatEx(sQuery, 128, "SELECT DISTINCT ip FROM %susers WHERE ip LIKE '%%.%%';", gS_SQLPrefix); if (gI_Driver == Driver_mysql)
{
FormatEx(sQuery, 128, "SELECT DISTINCT ip FROM %susers WHERE ip LIKE '%%.%%';", gS_SQLPrefix);
}
else if (gI_Driver == Driver_pgsql)
{
FormatEx(sQuery, 128, "SELECT DISTINCT ip FROM %susers WHERE ip LIKE '%%.%%';", gS_SQLPrefix);
}
else // SQLite
{
FormatEx(sQuery, 128, "SELECT DISTINCT ip FROM %susers WHERE ip LIKE '%%.%%';", gS_SQLPrefix);
}
QueryLog(gH_SQL, SQL_TableMigrationIPAddresses_Callback, sQuery); QueryLog(gH_SQL, SQL_TableMigrationIPAddresses_Callback, sQuery);
} }
@ -973,10 +1341,32 @@ public void Trans_IPAddressMigrationSuccess(Database db, any data, int numQuerie
} }
char sQuery[128]; char sQuery[128];
FormatEx(sQuery, 128, "ALTER TABLE `%susers` DROP INDEX `ip`;", gS_SQLPrefix); if (gI_Driver == Driver_mysql)
{
FormatEx(sQuery, 128, "ALTER TABLE `%susers` DROP INDEX `ip`;", gS_SQLPrefix);
}
else if (gI_Driver == Driver_pgsql)
{
FormatEx(sQuery, 128, "DROP INDEX IF EXISTS ip;");
}
else // SQLite
{
FormatEx(sQuery, 128, "DROP INDEX IF EXISTS ip;");
}
QueryLog(gH_SQL, SQL_TableMigrationIndexing_Callback, sQuery, 0, DBPrio_High); QueryLog(gH_SQL, SQL_TableMigrationIndexing_Callback, sQuery, 0, DBPrio_High);
FormatEx(sQuery, 128, "ALTER TABLE `%susers` CHANGE COLUMN `ip` `ip` INT;", gS_SQLPrefix); if (gI_Driver == Driver_mysql)
{
FormatEx(sQuery, 128, "ALTER TABLE `%susers` CHANGE COLUMN `ip` `ip` INT;", gS_SQLPrefix);
}
else if (gI_Driver == Driver_pgsql)
{
FormatEx(sQuery, 128, "ALTER TABLE %susers ALTER COLUMN ip TYPE INT USING ip::INT;", gS_SQLPrefix);
}
else // SQLite - doesn't support ALTER COLUMN type changes
{
FormatEx(sQuery, 128, "-- SQLite doesn't support ALTER COLUMN type changes");
}
QueryLog(gH_SQL, SQL_TableMigrationSingleQuery_Callback, sQuery, Migration_ConvertIPAddresses, DBPrio_High); QueryLog(gH_SQL, SQL_TableMigrationSingleQuery_Callback, sQuery, Migration_ConvertIPAddresses, DBPrio_High);
} }

View File

@ -409,7 +409,18 @@ public void SQL_FillTierCache_Callback(Database db, DBResultSet results, const c
Call_Finish(); Call_Finish();
char sQuery[512]; char sQuery[512];
FormatEx(sQuery, sizeof(sQuery), "REPLACE INTO %smaptiers (map, tier) VALUES ('%s', %d);", gS_MySQLPrefix, gS_Map, gI_Tier); if (gI_Driver == Driver_mysql)
{
FormatEx(sQuery, sizeof(sQuery), "REPLACE INTO %smaptiers (map, tier) VALUES ('%s', %d);", gS_MySQLPrefix, gS_Map, gI_Tier);
}
else if (gI_Driver == Driver_pgsql)
{
FormatEx(sQuery, sizeof(sQuery), "INSERT INTO %smaptiers (map, tier) VALUES ('%s', %d) ON CONFLICT (map) DO UPDATE SET tier = EXCLUDED.tier;", gS_MySQLPrefix, gS_Map, gI_Tier);
}
else // SQLite
{
FormatEx(sQuery, sizeof(sQuery), "INSERT OR REPLACE INTO %smaptiers (map, tier) VALUES ('%s', %d);", gS_MySQLPrefix, gS_Map, gI_Tier);
}
QueryLog(gH_SQL, SQL_SetMapTier_Callback, sQuery, 0, DBPrio_High); QueryLog(gH_SQL, SQL_SetMapTier_Callback, sQuery, 0, DBPrio_High);
} }
} }
@ -669,7 +680,18 @@ public Action Command_SetTier(int client, int args)
Shavit_LogMessage("%L - set tier of `%s` to %d", client, gS_Map, tier); Shavit_LogMessage("%L - set tier of `%s` to %d", client, gS_Map, tier);
char sQuery[512]; char sQuery[512];
FormatEx(sQuery, sizeof(sQuery), "REPLACE INTO %smaptiers (map, tier) VALUES ('%s', %d);", gS_MySQLPrefix, map, tier); if (gI_Driver == Driver_mysql)
{
FormatEx(sQuery, sizeof(sQuery), "REPLACE INTO %smaptiers (map, tier) VALUES ('%s', %d);", gS_MySQLPrefix, map, tier);
}
else if (gI_Driver == Driver_pgsql)
{
FormatEx(sQuery, sizeof(sQuery), "INSERT INTO %smaptiers (map, tier) VALUES ('%s', %d) ON CONFLICT (map) DO UPDATE SET tier = EXCLUDED.tier;", gS_MySQLPrefix, map, tier);
}
else // SQLite
{
FormatEx(sQuery, sizeof(sQuery), "INSERT OR REPLACE INTO %smaptiers (map, tier) VALUES ('%s', %d);", gS_MySQLPrefix, map, tier);
}
DataPack data = new DataPack(); DataPack data = new DataPack();
data.WriteCell(client ? GetClientSerial(client) : 0); data.WriteCell(client ? GetClientSerial(client) : 0);
@ -788,7 +810,7 @@ void FormatRecalculate(bool bUseCurrentMap, int track, int style, char[] sQuery,
gS_Map gS_Map
); );
} }
else else if (gI_Driver == Driver_mysql)
{ {
FormatEx(sQuery, sQueryLen, FormatEx(sQuery, sQueryLen,
"UPDATE %splayertimes AS PT " ... "UPDATE %splayertimes AS PT " ...
@ -808,6 +830,27 @@ void FormatRecalculate(bool bUseCurrentMap, int track, int style, char[] sQuery,
gS_Map gS_Map
); );
} }
else // PostgreSQL
{
FormatEx(sQuery, sQueryLen,
"UPDATE %splayertimes AS PT " ...
"SET " ...
" points = "...
" (%f + (WR.time / 15.0)) " ...
" * (WR.time / PT.time) " ...
" * %f " ...
"FROM %swrs WR " ...
"WHERE PT.track = WR.track AND PT.style = WR.style AND PT.map = WR.map " ...
" AND PT.track %c 0 AND PT.style = %d AND PT.map = '%s';",
gS_MySQLPrefix,
((gCV_PointsPerTier.FloatValue * fTier) * 1.5),
fMultiplier,
gS_MySQLPrefix,
(track > 0) ? '>' : '=',
style,
gS_Map
);
}
} }
else if (gI_Driver == Driver_sqlite) else if (gI_Driver == Driver_sqlite)
{ {
@ -835,7 +878,7 @@ void FormatRecalculate(bool bUseCurrentMap, int track, int style, char[] sQuery,
mapfilter mapfilter
); );
} }
else else if (gI_Driver == Driver_mysql)
{ {
char mapfilter[50+PLATFORM_MAX_PATH]; char mapfilter[50+PLATFORM_MAX_PATH];
if (map[0]) FormatEx(mapfilter, sizeof(mapfilter), "AND PT.map = '%s'", map); if (map[0]) FormatEx(mapfilter, sizeof(mapfilter), "AND PT.map = '%s'", map);
@ -862,6 +905,32 @@ void FormatRecalculate(bool bUseCurrentMap, int track, int style, char[] sQuery,
fMultiplier fMultiplier
); );
} }
else // PostgreSQL
{
char mapfilter[50+PLATFORM_MAX_PATH];
if (map[0]) FormatEx(mapfilter, sizeof(mapfilter), "AND PT.map = '%s'", map);
FormatEx(sQuery, sQueryLen,
"UPDATE %splayertimes AS PT " ...
"SET " ...
" points = "...
" (((%f * %s) * 1.5) + (WR.time / 15.0)) " ...
" * (WR.time / PT.time) " ...
" * %f " ...
"FROM %swrs AS WR, %smaptiers AS MT " ...
"WHERE PT.track %c 0 AND PT.track = WR.track AND PT.style = %d AND PT.style = WR.style %s AND PT.map = WR.map " ...
" AND PT.map = MT.map;",
gS_MySQLPrefix,
gCV_PointsPerTier.FloatValue,
(track > 0) ? "1" : "MT.tier",
fMultiplier,
gS_MySQLPrefix,
gS_MySQLPrefix,
(track > 0) ? '>' : '=',
style,
mapfilter
);
}
} }
public Action Command_RecalcAll(int client, int args) public Action Command_RecalcAll(int client, int args)
@ -1098,7 +1167,7 @@ void UpdateAllPoints(bool recalcall=false, char[] map="", int track=-1)
if (sLastLogin[0]) if (sLastLogin[0])
Format(sLastLogin, sizeof(sLastLogin), "u2.%s", sLastLogin); Format(sLastLogin, sizeof(sLastLogin), "u2.%s", sLastLogin);
// fuck you mysql // MySQL-specific JOIN syntax
FormatEx(sQuery, sizeof(sQuery), FormatEx(sQuery, sizeof(sQuery),
"UPDATE %susers AS u, (\n" "UPDATE %susers AS u, (\n"
... " SELECT auth, SUM(t.points2) as pp FROM (\n" ... " SELECT auth, SUM(t.points2) as pp FROM (\n"
@ -1125,8 +1194,34 @@ void UpdateAllPoints(bool recalcall=false, char[] map="", int track=-1)
sTrackWhere, sTrackWhere,
sLimit); // TODO: Remove/move sLimit? sLimit); // TODO: Remove/move sLimit?
} }
else if (gB_SQLWindowFunctions && gI_Driver == Driver_pgsql)
{
// PostgreSQL-specific syntax (similar to standard SQL)
FormatEx(sQuery, sizeof(sQuery),
"UPDATE %susers AS u\n"
... "SET points = (\n"
... " SELECT SUM(points2) FROM (\n"
... " SELECT (points * POWER(%f, ROW_NUMBER() OVER (ORDER BY points DESC) - 1)) AS points2\n"
... " FROM %splayertimes\n"
... " WHERE auth = u.auth AND points > 0\n"
... " ORDER BY points DESC %s\n"
... " ) AS t\n"
... ") WHERE %s %s auth IN\n"
... " (SELECT DISTINCT auth FROM %splayertimes %s %s %s %s);",
gS_MySQLPrefix,
gCV_WeightingMultiplier.FloatValue,
gS_MySQLPrefix,
sLimit, // TODO: Remove/move sLimit?
sLastLogin, sLastLogin[0] ? "AND" : "",
gS_MySQLPrefix,
(sMapWhere[0] || sTrackWhere[0]) ? "WHERE" : "",
sMapWhere,
(sMapWhere[0] && sTrackWhere[0]) ? "AND" : "",
sTrackWhere);
}
else if (gB_SQLWindowFunctions) else if (gB_SQLWindowFunctions)
{ {
// Standard SQL window functions (SQLite and other databases)
FormatEx(sQuery, sizeof(sQuery), FormatEx(sQuery, sizeof(sQuery),
"UPDATE %susers AS u\n" "UPDATE %susers AS u\n"
... "SET points = (\n" ... "SET points = (\n"
@ -1194,8 +1289,21 @@ void UpdatePlayerRank(int client, bool first)
// if there's any issue with this query, // if there's any issue with this query,
// add "ORDER BY points DESC " before "LIMIT 1" // add "ORDER BY points DESC " before "LIMIT 1"
char sQuery[512]; char sQuery[512];
FormatEx(sQuery, 512, "SELECT u2.points, COUNT(*) FROM %susers u1 JOIN (SELECT points FROM %susers WHERE auth = %d) u2 WHERE u1.points >= u2.points;", if (gI_Driver == Driver_mysql)
gS_MySQLPrefix, gS_MySQLPrefix, iSteamID); {
FormatEx(sQuery, 512, "SELECT u2.points, COUNT(*) FROM %susers u1 JOIN (SELECT points FROM %susers WHERE auth = %d) u2 WHERE u1.points >= u2.points;",
gS_MySQLPrefix, gS_MySQLPrefix, iSteamID);
}
else if (gI_Driver == Driver_pgsql)
{
FormatEx(sQuery, 512, "SELECT u2.points, COUNT(*) FROM %susers u1 CROSS JOIN (SELECT points FROM %susers WHERE auth = %d) u2 WHERE u1.points >= u2.points GROUP BY u2.points;",
gS_MySQLPrefix, gS_MySQLPrefix, iSteamID);
}
else // SQLite
{
FormatEx(sQuery, 512, "SELECT u2.points, COUNT(*) FROM %susers u1 JOIN (SELECT points FROM %susers WHERE auth = %d) u2 WHERE u1.points >= u2.points;",
gS_MySQLPrefix, gS_MySQLPrefix, iSteamID);
}
DataPack hPack = new DataPack(); DataPack hPack = new DataPack();
hPack.WriteCell(GetClientSerial(client)); hPack.WriteCell(GetClientSerial(client));
@ -1245,11 +1353,30 @@ public void SQL_UpdatePlayerRank_Callback(Database db, DBResultSet results, cons
void UpdateTop100() void UpdateTop100()
{ {
char sQuery[512]; char sQuery[512];
FormatEx(sQuery, sizeof(sQuery), if (gI_Driver == Driver_mysql)
"SELECT * FROM (SELECT COUNT(*) as c, 0 as auth, '' as name, '' as p FROM %susers WHERE points > 0) a \ {
UNION ALL \ FormatEx(sQuery, sizeof(sQuery),
SELECT * FROM (SELECT -1 as c, auth, name, FORMAT(points, 2) FROM %susers WHERE points > 0 ORDER BY points DESC LIMIT 100) b;", "SELECT * FROM (SELECT COUNT(*) as c, 0 as auth, '' as name, '' as p FROM %susers WHERE points > 0) a \
gS_MySQLPrefix, gS_MySQLPrefix); UNION ALL \
SELECT * FROM (SELECT -1 as c, auth, name, FORMAT(points, 2) FROM %susers WHERE points > 0 ORDER BY points DESC LIMIT 100) b;",
gS_MySQLPrefix, gS_MySQLPrefix);
}
else if (gI_Driver == Driver_pgsql)
{
FormatEx(sQuery, sizeof(sQuery),
"SELECT * FROM (SELECT COUNT(*) as c, 0 as auth, '' as name, '' as p FROM %susers WHERE points > 0) a \
UNION ALL \
SELECT * FROM (SELECT -1 as c, auth, name, ROUND(points::numeric, 2)::text FROM %susers WHERE points > 0 ORDER BY points DESC LIMIT 100) b;",
gS_MySQLPrefix, gS_MySQLPrefix);
}
else // SQLite
{
FormatEx(sQuery, sizeof(sQuery),
"SELECT * FROM (SELECT COUNT(*) as c, 0 as auth, '' as name, '' as p FROM %susers WHERE points > 0) a \
UNION ALL \
SELECT * FROM (SELECT -1 as c, auth, name, ROUND(points, 2) FROM %susers WHERE points > 0 ORDER BY points DESC LIMIT 100) b;",
gS_MySQLPrefix, gS_MySQLPrefix);
}
QueryLog(gH_SQL, SQL_UpdateTop100_Callback, sQuery, 0, DBPrio_High); QueryLog(gH_SQL, SQL_UpdateTop100_Callback, sQuery, 0, DBPrio_High);
} }
@ -1304,23 +1431,67 @@ public void SQL_UpdateTop100_Callback(Database db, DBResultSet results, const ch
bool DoWeHaveWindowFunctions(const char[] sVersion) bool DoWeHaveWindowFunctions(const char[] sVersion)
{ {
char buf[100][2];
ExplodeString(sVersion, ".", buf, 2, 100);
int iMajor = StringToInt(buf[0]);
int iMinor = StringToInt(buf[1]);
if (gI_Driver == Driver_sqlite) if (gI_Driver == Driver_sqlite)
{ {
char buf[100][2];
ExplodeString(sVersion, ".", buf, 2, 100);
int iMajor = StringToInt(buf[0]);
int iMinor = StringToInt(buf[1]);
// 2018~ // 2018~
return iMajor > 3 || (iMajor == 3 && iMinor >= 25); // 2018~ return iMajor > 3 || (iMajor == 3 && iMinor >= 25); // 2018~
} }
else if (gI_Driver == Driver_pgsql) else if (gI_Driver == Driver_pgsql)
{ {
// 2009~ // PostgreSQL version string format: "PostgreSQL 16.1 on x86_64-pc-linux-gnu..."
// Extract version number after "PostgreSQL "
char sVersionCopy[100];
strcopy(sVersionCopy, sizeof(sVersionCopy), sVersion);
int iStart = StrContains(sVersionCopy, "PostgreSQL ");
if (iStart != -1)
{
iStart += 11; // Length of "PostgreSQL "
char sVersionPart[32];
strcopy(sVersionPart, sizeof(sVersionPart), sVersionCopy[iStart]);
// Find first space to terminate version string
int iEnd = StrContains(sVersionPart, " ");
if (iEnd != -1)
{
sVersionPart[iEnd] = '\0';
}
char buf[32][2];
ExplodeString(sVersionPart, ".", buf, 2, 32);
int iMajor = StringToInt(buf[0]);
int iMinor = StringToInt(buf[1]);
// PostgreSQL has had window functions since 8.4 (2009)
// But modern PostgreSQL uses major.minor format where major >= 10
if (iMajor >= 10)
{
return true; // All PostgreSQL 10+ have window functions
}
else
{
return iMajor > 8 || (iMajor == 8 && iMinor >= 4);
}
}
// Fallback: assume old format and check anyway
char buf[100][2];
ExplodeString(sVersion, ".", buf, 2, 100);
int iMajor = StringToInt(buf[0]);
int iMinor = StringToInt(buf[1]);
return iMajor > 8 || (iMajor == 8 && iMinor >= 4); return iMajor > 8 || (iMajor == 8 && iMinor >= 4);
} }
else if (gI_Driver == Driver_mysql) else if (gI_Driver == Driver_mysql)
{ {
char buf[100][2];
ExplodeString(sVersion, ".", buf, 2, 100);
int iMajor = StringToInt(buf[0]);
int iMinor = StringToInt(buf[1]);
if (StrContains(sVersion, "MariaDB") != -1) if (StrContains(sVersion, "MariaDB") != -1)
{ {
// 2016~ // 2016~
@ -1362,8 +1533,8 @@ public void SQL_Version_Callback(Database db, DBResultSet results, const char[]
} }
else if (gI_Driver == Driver_pgsql) else if (gI_Driver == Driver_pgsql)
{ {
LogError("Okay, really? Your postgres version is from 2014 or earlier... come on, brother..."); LogError("PostgreSQL version does not support window functions. Window functions require PostgreSQL 8.4 or later.");
SetFailState("Update postgresql"); SetFailState("Update PostgreSQL to version 8.4 or later");
} }
else // mysql else // mysql
{ {

View File

@ -49,6 +49,7 @@ bool gB_Rankings = false;
// database handle // database handle
Database gH_SQL = null; Database gH_SQL = null;
char gS_MySQLPrefix[32]; char gS_MySQLPrefix[32];
int gI_Driver = Driver_unknown;
// cache // cache
bool gB_CanOpenMenu[MAXPLAYERS+1]; bool gB_CanOpenMenu[MAXPLAYERS+1];
@ -187,7 +188,7 @@ void FlushDisconnectPlaytime()
public void Shavit_OnDatabaseLoaded() public void Shavit_OnDatabaseLoaded()
{ {
GetTimerSQLPrefix(gS_MySQLPrefix, 32); GetTimerSQLPrefix(gS_MySQLPrefix, 32);
gH_SQL = Shavit_GetDatabase(); gH_SQL = Shavit_GetDatabase(gI_Driver);
for (int i = 1; i <= MaxClients; i++) for (int i = 1; i <= MaxClients; i++)
{ {
@ -425,9 +426,18 @@ void SavePlaytime222(int client, float now, Transaction&trans, int style, int iS
return; return;
} }
FormatEx(sQuery, sizeof(sQuery), if (gI_Driver == Driver_mysql)
"UPDATE `%susers` SET playtime = playtime + %f WHERE auth = %d;", {
gS_MySQLPrefix, diff, iSteamID); FormatEx(sQuery, sizeof(sQuery),
"UPDATE `%susers` SET playtime = playtime + %f WHERE auth = %d;",
gS_MySQLPrefix, diff, iSteamID);
}
else // PostgreSQL/SQLite
{
FormatEx(sQuery, sizeof(sQuery),
"UPDATE %susers SET playtime = playtime + %f WHERE auth = %d;",
gS_MySQLPrefix, diff, iSteamID);
}
} }
else else
{ {
@ -448,16 +458,34 @@ void SavePlaytime222(int client, float now, Transaction&trans, int style, int iS
if (gB_HavePlaytimeOnStyle[client][style]) if (gB_HavePlaytimeOnStyle[client][style])
{ {
FormatEx(sQuery, sizeof(sQuery), if (gI_Driver == Driver_mysql)
"UPDATE `%sstyleplaytime` SET playtime = playtime + %f WHERE auth = %d AND style = %d;", {
gS_MySQLPrefix, diff, iSteamID, style); FormatEx(sQuery, sizeof(sQuery),
"UPDATE `%sstyleplaytime` SET playtime = playtime + %f WHERE auth = %d AND style = %d;",
gS_MySQLPrefix, diff, iSteamID, style);
}
else // PostgreSQL/SQLite
{
FormatEx(sQuery, sizeof(sQuery),
"UPDATE %sstyleplaytime SET playtime = playtime + %f WHERE auth = %d AND style = %d;",
gS_MySQLPrefix, diff, iSteamID, style);
}
} }
else else
{ {
gB_HavePlaytimeOnStyle[client][style] = true; gB_HavePlaytimeOnStyle[client][style] = true;
FormatEx(sQuery, sizeof(sQuery), if (gI_Driver == Driver_mysql)
"INSERT INTO `%sstyleplaytime` (`auth`, `style`, `playtime`) VALUES (%d, %d, %f);", {
gS_MySQLPrefix, iSteamID, style, diff); FormatEx(sQuery, sizeof(sQuery),
"INSERT INTO `%sstyleplaytime` (`auth`, `style`, `playtime`) VALUES (%d, %d, %f);",
gS_MySQLPrefix, iSteamID, style, diff);
}
else // PostgreSQL/SQLite
{
FormatEx(sQuery, sizeof(sQuery),
"INSERT INTO %sstyleplaytime (auth, style, playtime) VALUES (%d, %d, %f);",
gS_MySQLPrefix, iSteamID, style, diff);
}
} }
} }
@ -554,11 +582,23 @@ public Action Command_Playtime(int client, int args)
} }
char sQuery[512]; char sQuery[512];
FormatEx(sQuery, sizeof(sQuery),
"(SELECT auth, name, playtime, -1 as ownrank FROM %susers WHERE playtime > 0 ORDER BY playtime DESC LIMIT 100) " ... if (gI_Driver == Driver_mysql)
"UNION " ... {
"(SELECT -1, '', u2.playtime, COUNT(*) as ownrank FROM %susers u1 JOIN (SELECT playtime FROM %susers WHERE auth = %d) u2 WHERE u1.playtime >= u2.playtime);", FormatEx(sQuery, sizeof(sQuery),
gS_MySQLPrefix, gS_MySQLPrefix, gS_MySQLPrefix, GetSteamAccountID(client)); "(SELECT auth, name, playtime, -1 as ownrank FROM %susers WHERE playtime > 0 ORDER BY playtime DESC LIMIT 100) " ...
"UNION " ...
"(SELECT -1, '', u2.playtime, COUNT(*) as ownrank FROM %susers u1 JOIN (SELECT playtime FROM %susers WHERE auth = %d) u2 WHERE u1.playtime >= u2.playtime);",
gS_MySQLPrefix, gS_MySQLPrefix, gS_MySQLPrefix, GetSteamAccountID(client));
}
else // PostgreSQL/SQLite
{
FormatEx(sQuery, sizeof(sQuery),
"(SELECT auth, name, playtime, -1 as ownrank FROM %susers WHERE playtime > 0 ORDER BY playtime DESC LIMIT 100) " ...
"UNION " ...
"(SELECT -1, ''::TEXT, u2.playtime, COUNT(*)::INT as ownrank FROM %susers u1 JOIN (SELECT playtime FROM %susers WHERE auth = %d) u2 WHERE u1.playtime >= u2.playtime);",
gS_MySQLPrefix, gS_MySQLPrefix, gS_MySQLPrefix, GetSteamAccountID(client));
}
QueryLog(gH_SQL, SQL_TopPlaytime_Callback, sQuery, GetClientSerial(client), DBPrio_Normal); QueryLog(gH_SQL, SQL_TopPlaytime_Callback, sQuery, GetClientSerial(client), DBPrio_Normal);
return Plugin_Handled; return Plugin_Handled;
@ -819,13 +859,39 @@ Action OpenStatsMenu(int client, int steamid, int style = 0, int item = 0)
if (gB_Mapchooser && gCV_UseMapchooser.BoolValue) if (gB_Mapchooser && gCV_UseMapchooser.BoolValue)
{ {
char sQuery[2048]; char sQuery[2048];
FormatEx(sQuery, sizeof(sQuery),
// Note the `GROUP BY track>0` for now if (gI_Driver == Driver_mysql)
"SELECT 0 as blah, map, track>0 FROM %splayertimes WHERE auth = %d AND style = %d GROUP BY map, track>0 " ... {
"UNION SELECT 1 as blah, map, track>0 FROM %smapzones WHERE type = 0 GROUP BY map, track>0 " ... // MySQL/SQLite: original query
"UNION SELECT 2 as blah, map, track FROM %swrs WHERE auth = %d AND style = %d GROUP BY map, track;", FormatEx(sQuery, sizeof(sQuery),
gS_MySQLPrefix, steamid, style, gS_MySQLPrefix, gS_MySQLPrefix, steamid, style // Note the `GROUP BY track>0` for now
); "SELECT 0 as blah, map, track>0 FROM %splayertimes WHERE auth = %d AND style = %d GROUP BY map, track>0 " ...
"UNION SELECT 1 as blah, map, track>0 FROM %smapzones WHERE type = 0 GROUP BY map, track>0 " ...
"UNION SELECT 2 as blah, map, track FROM %swrs WHERE auth = %d AND style = %d GROUP BY map, track;",
gS_MySQLPrefix, steamid, style, gS_MySQLPrefix, gS_MySQLPrefix, steamid, style
);
}
else if (gI_Driver == Driver_pgsql)
{
// PostgreSQL: cast track to boolean to match track>0
FormatEx(sQuery, sizeof(sQuery),
"SELECT 0 as blah, map, track>0 FROM %splayertimes WHERE auth = %d AND style = %d GROUP BY map, track>0 " ...
"UNION SELECT 1 as blah, map, track>0 FROM %smapzones WHERE type = 0 GROUP BY map, track>0 " ...
"UNION SELECT 2 as blah, map, track>0 FROM %swrs WHERE auth = %d AND style = %d GROUP BY map, track>0;",
gS_MySQLPrefix, steamid, style, gS_MySQLPrefix, gS_MySQLPrefix, steamid, style
);
}
else // SQLite
{
// SQLite: same as MySQL
FormatEx(sQuery, sizeof(sQuery),
// Note the `GROUP BY track>0` for now
"SELECT 0 as blah, map, track>0 FROM %splayertimes WHERE auth = %d AND style = %d GROUP BY map, track>0 " ...
"UNION SELECT 1 as blah, map, track>0 FROM %smapzones WHERE type = 0 GROUP BY map, track>0 " ...
"UNION SELECT 2 as blah, map, track FROM %swrs WHERE auth = %d AND style = %d GROUP BY map, track;",
gS_MySQLPrefix, steamid, style, gS_MySQLPrefix, gS_MySQLPrefix, steamid, style
);
}
QueryLog(gH_SQL, OpenStatsMenu_Mapchooser_Callback, sQuery, data, DBPrio_Low); QueryLog(gH_SQL, OpenStatsMenu_Mapchooser_Callback, sQuery, data, DBPrio_Low);
@ -889,31 +955,65 @@ Action OpenStatsMenu_Main(int steamid, int style, DataPack data)
{ {
char sQuery[2048]; char sQuery[2048];
FormatEx(sQuery, sizeof(sQuery), if (gI_Driver == Driver_mysql)
"SELECT 0, points, lastlogin, firstlogin, ip, playtime, name FROM %susers WHERE auth = %d\n" ... {
"UNION ALL SELECT 1, SUM(playtime), 0, 0, 0, 0, '' FROM %sstyleplaytime WHERE auth = %d AND style = %d\n" ... FormatEx(sQuery, sizeof(sQuery),
"UNION ALL SELECT 2, COUNT(*), 0, 0, 0, 0, '' FROM %susers u1\n" ... "SELECT 0, points, lastlogin, firstlogin, ip, playtime, name FROM %susers WHERE auth = %d\n" ...
" JOIN (SELECT points FROM %susers WHERE auth = %d) u2\n" ... "UNION ALL SELECT 1, SUM(playtime), 0, 0, 0, 0, '' FROM %sstyleplaytime WHERE auth = %d AND style = %d\n" ...
" WHERE u1.points >= u2.points", "UNION ALL SELECT 2, COUNT(*), 0, 0, 0, 0, '' FROM %susers u1\n" ...
gS_MySQLPrefix, steamid, " JOIN (SELECT points FROM %susers WHERE auth = %d) u2 ON 1=1\n" ...
gS_MySQLPrefix, steamid, style, " WHERE u1.points >= u2.points",
gS_MySQLPrefix, gS_MySQLPrefix, steamid gS_MySQLPrefix, steamid,
); gS_MySQLPrefix, steamid, style,
gS_MySQLPrefix, gS_MySQLPrefix, steamid
);
}
else // PostgreSQL/SQLite
{
FormatEx(sQuery, sizeof(sQuery),
"SELECT 0, points::FLOAT, lastlogin, firstlogin, ip, playtime::FLOAT, name FROM %susers WHERE auth = %d\n" ...
"UNION ALL SELECT 1, SUM(playtime)::FLOAT, 0, 0, 0, 0.0, '' FROM %sstyleplaytime WHERE auth = %d AND style = %d\n" ...
"UNION ALL SELECT 2, COUNT(*)::FLOAT, 0, 0, 0, 0.0, '' FROM %susers u1\n" ...
" JOIN (SELECT points FROM %susers WHERE auth = %d) u2 ON 1=1\n" ...
" WHERE u1.points >= u2.points",
gS_MySQLPrefix, steamid,
gS_MySQLPrefix, steamid, style,
gS_MySQLPrefix, gS_MySQLPrefix, steamid
);
}
if (!gB_Mapchooser || !gCV_UseMapchooser.BoolValue) if (!gB_Mapchooser || !gCV_UseMapchooser.BoolValue)
{ {
Format(sQuery, sizeof(sQuery), if (gI_Driver == Driver_mysql)
"%s\n" ... {
"UNION ALL SELECT 3, COUNT(*), x.bonus, 0, 0, '' FROM\n"... Format(sQuery, sizeof(sQuery),
" (SELECT map, track>0 as bonus FROM %splayertimes WHERE auth = %d AND style = %d GROUP BY map, track>0) x GROUP BY x.bonus\n"... "%s\n" ...
"UNION ALL SELECT 4, COUNT(*), track>0, 0, 0, '' FROM %swrs WHERE auth = %d AND style = %d GROUP BY track>0\n"... "UNION ALL SELECT 3, COUNT(*), x.bonus, 0, 0, 0, '' FROM\n"...
"UNION ALL SELECT 5, COUNT(*), x.bonus, 0, 0, '' FROM\n"... " (SELECT map, track>0 as bonus FROM %splayertimes WHERE auth = %d AND style = %d GROUP BY map, track>0) x GROUP BY x.bonus\n"...
" (SELECT map, track>0 as bonus FROM %smapzones WHERE type = 0 GROUP BY map, track>0) x GROUP BY x.bonus", "UNION ALL SELECT 4, COUNT(*), track>0, 0, 0, 0, '' FROM %swrs WHERE auth = %d AND style = %d GROUP BY track>0\n"...
sQuery, "UNION ALL SELECT 5, COUNT(*), x.bonus, 0, 0, 0, '' FROM\n"...
gS_MySQLPrefix, steamid, style, " (SELECT map, track>0 as bonus FROM %smapzones WHERE type = 0 GROUP BY map, track>0) x GROUP BY x.bonus",
gS_MySQLPrefix, steamid, style, sQuery,
gS_MySQLPrefix gS_MySQLPrefix, steamid, style,
); gS_MySQLPrefix, steamid, style,
gS_MySQLPrefix
);
}
else // PostgreSQL/SQLite
{
Format(sQuery, sizeof(sQuery),
"%s\n" ...
"UNION ALL SELECT 3, COUNT(*)::FLOAT, CASE WHEN x.bonus THEN 1 ELSE 0 END, 0, 0, 0.0, '' FROM\n"...
" (SELECT map, track>0 as bonus FROM %splayertimes WHERE auth = %d AND style = %d GROUP BY map, track>0) x GROUP BY x.bonus\n"...
"UNION ALL SELECT 4, COUNT(*)::FLOAT, CASE WHEN track>0 THEN 1 ELSE 0 END, 0, 0, 0.0, '' FROM %swrs WHERE auth = %d AND style = %d GROUP BY track>0\n"...
"UNION ALL SELECT 5, COUNT(*)::FLOAT, CASE WHEN x.bonus THEN 1 ELSE 0 END, 0, 0, 0.0, '' FROM\n"...
" (SELECT map, track>0 as bonus FROM %smapzones WHERE type = 0 GROUP BY map, track>0) x GROUP BY x.bonus",
sQuery,
gS_MySQLPrefix, steamid, style,
gS_MySQLPrefix, steamid, style,
gS_MySQLPrefix
);
}
} }
StrCat(sQuery, sizeof(sQuery), ";"); StrCat(sQuery, sizeof(sQuery), ";");

View File

@ -535,7 +535,20 @@ void UpdateClientCache(int client)
} }
char sQuery[512]; char sQuery[512];
FormatEx(sQuery, sizeof(sQuery), "SELECT %s, style, track, completions FROM %splayertimes WHERE map = '%s' AND auth = %d;", gI_Driver == Driver_mysql ? "REPLACE(FORMAT(time, 9), ',', '')" : "printf(\"%.9f\", time)", gS_MySQLPrefix, gS_Map, iSteamID); char sTimeFormat[64];
if (gI_Driver == Driver_mysql)
{
strcopy(sTimeFormat, sizeof(sTimeFormat), "REPLACE(FORMAT(time, 9), ',', '')");
}
else if (gI_Driver == Driver_pgsql)
{
strcopy(sTimeFormat, sizeof(sTimeFormat), "time::text");
}
else // SQLite
{
strcopy(sTimeFormat, sizeof(sTimeFormat), "printf(\"%.9f\", time)");
}
FormatEx(sQuery, sizeof(sQuery), "SELECT %s, style, track, completions FROM %splayertimes WHERE map = '%s' AND auth = %d;", sTimeFormat, gS_MySQLPrefix, gS_Map, iSteamID);
QueryLog(gH_SQL, SQL_UpdateCache_Callback, sQuery, GetClientSerial(client), DBPrio_High); QueryLog(gH_SQL, SQL_UpdateCache_Callback, sQuery, GetClientSerial(client), DBPrio_High);
} }
@ -601,9 +614,24 @@ void UpdateWRCache(int client = -1)
char sQuery[512]; char sQuery[512];
FormatEx(sQuery, sizeof(sQuery), if (gI_Driver == Driver_mysql)
"SELECT style, track, auth, stage, time FROM `%sstagetimeswr` WHERE map = '%s';", {
gS_MySQLPrefix, gS_Map); FormatEx(sQuery, sizeof(sQuery),
"SELECT style, track, auth, stage, time FROM `%sstagetimeswr` WHERE map = '%s';",
gS_MySQLPrefix, gS_Map);
}
else if (gI_Driver == Driver_pgsql)
{
FormatEx(sQuery, sizeof(sQuery),
"SELECT style, track, auth, stage, time FROM %sstagetimeswr WHERE map = '%s';",
gS_MySQLPrefix, gS_Map);
}
else // SQLite
{
FormatEx(sQuery, sizeof(sQuery),
"SELECT style, track, auth, stage, time FROM `%sstagetimeswr` WHERE map = '%s';",
gS_MySQLPrefix, gS_Map);
}
QueryLog(gH_SQL, SQL_UpdateWRStageTimes_Callback, sQuery); QueryLog(gH_SQL, SQL_UpdateWRStageTimes_Callback, sQuery);
} }
@ -2750,10 +2778,27 @@ public void Shavit_OnFinish(int client, int style, float time, int jumps, int st
Transaction trans = new Transaction(); Transaction trans = new Transaction();
char query[512]; char query[512];
FormatEx(query, sizeof(query), if (gI_Driver == Driver_mysql)
"DELETE FROM `%sstagetimeswr` WHERE style = %d AND track = %d AND map = '%s';", {
gS_MySQLPrefix, style, track, gS_Map FormatEx(query, sizeof(query),
); "DELETE FROM `%sstagetimeswr` WHERE style = %d AND track = %d AND map = '%s';",
gS_MySQLPrefix, style, track, gS_Map
);
}
else if (gI_Driver == Driver_pgsql)
{
FormatEx(query, sizeof(query),
"DELETE FROM %sstagetimeswr WHERE style = %d AND track = %d AND map = '%s';",
gS_MySQLPrefix, style, track, gS_Map
);
}
else // SQLite
{
FormatEx(query, sizeof(query),
"DELETE FROM `%sstagetimeswr` WHERE style = %d AND track = %d AND map = '%s';",
gS_MySQLPrefix, style, track, gS_Map
);
}
AddQueryLog(trans, query); AddQueryLog(trans, query);
@ -2767,12 +2812,30 @@ public void Shavit_OnFinish(int client, int style, float time, int jumps, int st
continue; continue;
} }
FormatEx(query, sizeof(query), char sInsertQuery[512];
"INSERT INTO `%sstagetimeswr` (`style`, `track`, `map`, `auth`, `time`, `stage`) VALUES (%d, %d, '%s', %d, %f, %d);", if (gI_Driver == Driver_mysql)
gS_MySQLPrefix, style, track, gS_Map, iSteamID, fTime, i {
); FormatEx(sInsertQuery, sizeof(sInsertQuery),
"INSERT INTO `%sstagetimeswr` (`style`, `track`, `map`, `auth`, `time`, `stage`) VALUES (%d, %d, '%s', %d, %f, %d);",
gS_MySQLPrefix, style, track, gS_Map, iSteamID, fTime, i
);
}
else if (gI_Driver == Driver_pgsql)
{
FormatEx(sInsertQuery, sizeof(sInsertQuery),
"INSERT INTO %sstagetimeswr (style, track, map, auth, time, stage) VALUES (%d, %d, '%s', %d, %f, %d);",
gS_MySQLPrefix, style, track, gS_Map, iSteamID, fTime, i
);
}
else // SQLite
{
FormatEx(sInsertQuery, sizeof(sInsertQuery),
"INSERT INTO `%sstagetimeswr` (`style`, `track`, `map`, `auth`, `time`, `stage`) VALUES (%d, %d, '%s', %d, %f, %d);",
gS_MySQLPrefix, style, track, gS_Map, iSteamID, fTime, i
);
}
AddQueryLog(trans, query); AddQueryLog(trans, sInsertQuery);
} }
gH_SQL.Execute(trans, Trans_ReplaceStageTimes_Success, Trans_ReplaceStageTimes_Error, 0, DBPrio_High); gH_SQL.Execute(trans, Trans_ReplaceStageTimes_Success, Trans_ReplaceStageTimes_Error, 0, DBPrio_High);
@ -2984,7 +3047,20 @@ public void Trans_ReplaceStageTimes_Error(Database db, any data, int numQueries,
void UpdateLeaderboards() void UpdateLeaderboards()
{ {
char sQuery[512]; char sQuery[512];
FormatEx(sQuery, sizeof(sQuery), "SELECT p.style, p.track, %s, 0, p.id, p.auth, u.name FROM %splayertimes p LEFT JOIN %susers u ON p.auth = u.auth WHERE p.map = '%s' ORDER BY p.time ASC, p.date ASC;", gI_Driver == Driver_mysql ? "REPLACE(FORMAT(time, 9), ',', '')" : "printf(\"%.9f\", p.time)", gS_MySQLPrefix, gS_MySQLPrefix, gS_Map); char sTimeFormat[64];
if (gI_Driver == Driver_mysql)
{
strcopy(sTimeFormat, sizeof(sTimeFormat), "REPLACE(FORMAT(time, 9), ',', '')");
}
else if (gI_Driver == Driver_pgsql)
{
strcopy(sTimeFormat, sizeof(sTimeFormat), "p.time::text");
}
else // SQLite
{
strcopy(sTimeFormat, sizeof(sTimeFormat), "printf(\"%.9f\", p.time)");
}
FormatEx(sQuery, sizeof(sQuery), "SELECT p.style, p.track, %s, 0, p.id, p.auth, u.name FROM %splayertimes p LEFT JOIN %susers u ON p.auth = u.auth WHERE p.map = '%s' ORDER BY p.time ASC, p.date ASC;", sTimeFormat, gS_MySQLPrefix, gS_MySQLPrefix, gS_Map);
QueryLog(gH_SQL, SQL_UpdateLeaderboards_Callback, sQuery); QueryLog(gH_SQL, SQL_UpdateLeaderboards_Callback, sQuery);
} }

View File

@ -1923,11 +1923,27 @@ void SetStart(int client, int track, bool anglesonly)
char query[1024]; char query[1024];
FormatEx(query, sizeof(query), if (gI_Driver == Driver_mysql)
"REPLACE INTO %sstartpositions (auth, track, map, pos_x, pos_y, pos_z, ang_x, ang_y, ang_z, angles_only) VALUES (%d, %d, '%s', %.03f, %.03f, %.03f, %.03f, %.03f, %.03f, %d);", {
gS_MySQLPrefix, GetSteamAccountID(client), track, gS_Map, FormatEx(query, sizeof(query),
gF_StartPos[client][track][0], gF_StartPos[client][track][1], gF_StartPos[client][track][2], "REPLACE INTO %sstartpositions (auth, track, map, pos_x, pos_y, pos_z, ang_x, ang_y, ang_z, angles_only) VALUES (%d, %d, '%s', %.03f, %.03f, %.03f, %.03f, %.03f, %.03f, %d);",
gF_StartAng[client][track][0], gF_StartAng[client][track][1], gF_StartAng[client][track][2], anglesonly); gS_MySQLPrefix, GetSteamAccountID(client), track, gS_Map,
gF_StartPos[client][track][0], gF_StartPos[client][track][1], gF_StartPos[client][track][2],
gF_StartAng[client][track][0], gF_StartAng[client][track][1], gF_StartAng[client][track][2], anglesonly);
}
else // PostgreSQL/SQLite
{
FormatEx(query, sizeof(query),
"INSERT INTO %sstartpositions (auth, track, map, pos_x, pos_y, pos_z, ang_x, ang_y, ang_z, angles_only) VALUES (%d, %d, '%s', %.03f, %.03f, %.03f, %.03f, %.03f, %.03f, %s) " ...
"ON CONFLICT (auth, track, map) DO UPDATE SET " ...
"pos_x = EXCLUDED.pos_x, pos_y = EXCLUDED.pos_y, pos_z = EXCLUDED.pos_z, " ...
"ang_x = EXCLUDED.ang_x, ang_y = EXCLUDED.ang_y, ang_z = EXCLUDED.ang_z, " ...
"angles_only = EXCLUDED.angles_only;",
gS_MySQLPrefix, GetSteamAccountID(client), track, gS_Map,
gF_StartPos[client][track][0], gF_StartPos[client][track][1], gF_StartPos[client][track][2],
gF_StartAng[client][track][0], gF_StartAng[client][track][1], gF_StartAng[client][track][2],
anglesonly ? "true" : "false");
}
QueryLog(gH_SQL, SQL_InsertStartPosition_Callback, query); QueryLog(gH_SQL, SQL_InsertStartPosition_Callback, query);
} }