Try to cleanup DB api - DatabaseBackend now mainly just returns SQL query strings, with Database static class responsible for actually executing them

This commit is contained in:
UnknownShadow200 2020-09-27 00:16:07 +10:00
parent 4d1893c3d6
commit 7ac352770d
31 changed files with 278 additions and 217 deletions

View File

@ -112,27 +112,27 @@ namespace MCGalaxy.Blocks.Extended {
List<Vec3U16> coords = new List<Vec3U16>();
if (!ExistsInDB(map)) return coords;
Database.Backend.ReadRows("Messages" + map, "X,Y,Z", coords, Portal.ReadCoords);
Database.ReadRows("Messages" + map, "X,Y,Z", coords, Portal.ReadCoords);
return coords;
}
/// <summary> Deletes all message blocks for the given map. </summary>
public static void DeleteAll(string map) {
if (!ExistsInDB(map)) return;
Database.Backend.DeleteTable("Messages" + map);
Database.DeleteTable("Messages" + map);
}
/// <summary> Copies all message blocks from the given map to another map. </summary>
public static void CopyAll(string src, string dst) {
if (!ExistsInDB(src)) return;
Database.Backend.CreateTable("Messages" + dst, LevelDB.createMessages);
Database.Backend.CopyAllRows("Messages" + src, "Messages" + dst);
Database.CreateTable("Messages" + dst, LevelDB.createMessages);
Database.CopyAllRows("Messages" + src, "Messages" + dst);
}
/// <summary> Moves all message blocks from the given map to another map. </summary>
public static void MoveAll(string src, string dst) {
if (!ExistsInDB(src)) return;
Database.Backend.RenameTable("Messages" + src, "Messages" + dst);
Database.RenameTable("Messages" + src, "Messages" + dst);
}
@ -149,8 +149,8 @@ namespace MCGalaxy.Blocks.Extended {
/// <summary> Deletes the given message block from the given map. </summary>
public static void Delete(string map, ushort x, ushort y, ushort z) {
Database.Backend.DeleteRows("Messages" + map,
"WHERE X=@0 AND Y=@1 AND Z=@2", x, y, z);
Database.DeleteRows("Messages" + map,
"WHERE X=@0 AND Y=@1 AND Z=@2", x, y, z);
}
/// <summary> Creates or updates the given message block in the given map. </summary>
@ -159,15 +159,15 @@ namespace MCGalaxy.Blocks.Extended {
contents = Colors.Escape(contents);
contents = contents.UnicodeToCp437();
Database.Backend.CreateTable("Messages" + map, LevelDB.createMessages);
Database.CreateTable("Messages" + map, LevelDB.createMessages);
int count = Database.CountRows("Messages" + map,
"WHERE X=@0 AND Y=@1 AND Z=@2", x, y, z);
if (count == 0) {
Database.Backend.AddRow("Messages" + map, "X, Y, Z, Message", x, y, z, contents);
Database.AddRow("Messages" + map, "X, Y, Z, Message", x, y, z, contents);
} else {
Database.Backend.UpdateRows("Messages" + map, "Message=@3",
"WHERE X=@0 AND Y=@1 AND Z=@2", x, y, z, contents);
Database.UpdateRows("Messages" + map, "Message=@3",
"WHERE X=@0 AND Y=@1 AND Z=@2", x, y, z, contents);
}
Level lvl = LevelInfo.FindExact(map);

View File

@ -90,7 +90,7 @@ namespace MCGalaxy.Blocks.Extended {
List<Vec3U16> coords = new List<Vec3U16>();
if (!ExistsInDB(map)) return coords;
Database.Backend.ReadRows("Portals" + map, "EntryX,EntryY,EntryZ", coords, ReadCoords);
Database.ReadRows("Portals" + map, "EntryX,EntryY,EntryZ", coords, ReadCoords);
return coords;
}
@ -99,61 +99,60 @@ namespace MCGalaxy.Blocks.Extended {
List<PortalExit> exits = new List<PortalExit>();
if (!ExistsInDB(map)) return exits;
Database.Backend.ReadRows("Portals" + map, "ExitMap,ExitX,ExitY,ExitZ", exits, ReadAllExits);
Database.ReadRows("Portals" + map, "ExitMap,ExitX,ExitY,ExitZ", exits, ReadAllExits);
return exits;
}
/// <summary> Deletes all portals for the given map. </summary>
public static void DeleteAll(string map) {
if (!ExistsInDB(map)) return;
Database.Backend.DeleteTable("Portals" + map);
Database.DeleteTable("Portals" + map);
}
/// <summary> Copies all portals from the given map to another map. </summary>
public static void CopyAll(string src, string dst) {
if (!ExistsInDB(src)) return;
Database.Backend.CreateTable("Portals" + dst, LevelDB.createPortals);
Database.Backend.CopyAllRows("Portals" + src, "Portals" + dst);
Database.CreateTable("Portals" + dst, LevelDB.createPortals);
Database.CopyAllRows("Portals" + src, "Portals" + dst);
// Fixup portal exists that go to the same map
Database.Backend.UpdateRows("Portals" + dst, "ExitMap=@1", "WHERE ExitMap=@0", src, dst);
Database.UpdateRows("Portals" + dst, "ExitMap=@1", "WHERE ExitMap=@0", src, dst);
}
/// <summary> Moves all portals from the given map to another map. </summary>
public static void MoveAll(string src, string dst) {
if (!ExistsInDB(src)) return;
Database.Backend.RenameTable("Portals" + src, "Portals" + dst);
Database.RenameTable("Portals" + src, "Portals" + dst);
}
/// <summary> Returns the exit details for the given portal in the given map. </summary>
/// <remarks> Returns null if the given portal does not actually exist. </remarks>
public static PortalExit Get(string map, ushort x, ushort y, ushort z) {
object raw = Database.Backend.ReadRows("Portals" + map, "ExitMap,ExitX,ExitY,ExitZ",
null, ReadExit,
"WHERE EntryX=@0 AND EntryY=@1 AND EntryZ=@2", x, y, z);
object raw = Database.ReadRows("Portals" + map, "ExitMap,ExitX,ExitY,ExitZ", null, ReadExit,
"WHERE EntryX=@0 AND EntryY=@1 AND EntryZ=@2", x, y, z);
return (PortalExit)raw;
}
/// <summary> Deletes the given portal from the given map. </summary>
public static void Delete(string map, ushort x, ushort y, ushort z) {
Database.Backend.DeleteRows("Portals" + map,
"WHERE EntryX=@0 AND EntryY=@1 AND EntryZ=@2", x, y, z);
Database.DeleteRows("Portals" + map,
"WHERE EntryX=@0 AND EntryY=@1 AND EntryZ=@2", x, y, z);
}
/// <summary> Creates or updates the given portal in the given map. </summary>
public static void Set(string map, ushort x, ushort y, ushort z,
ushort exitX, ushort exitY, ushort exitZ, string exitMap) {
Database.Backend.CreateTable("Portals" + map, LevelDB.createPortals);
Database.CreateTable("Portals" + map, LevelDB.createPortals);
int count = Database.CountRows("Portals" + map,
"WHERE EntryX=@0 AND EntryY=@1 AND EntryZ=@2", x, y, z);
if (count == 0) {
Database.Backend.AddRow("Portals" + map, "EntryX, EntryY, EntryZ, ExitX, ExitY, ExitZ, ExitMap",
x, y, z, exitX, exitY, exitZ, exitMap);
Database.AddRow("Portals" + map, "EntryX, EntryY, EntryZ, ExitX, ExitY, ExitZ, ExitMap",
x, y, z, exitX, exitY, exitZ, exitMap);
} else {
Database.Backend.UpdateRows("Portals" + map, "ExitMap=@6, ExitX=@3, ExitY=@4, ExitZ=@5",
"WHERE EntryX=@0 AND EntryY=@1 AND EntryZ=@2", x, y, z,
exitX, exitY, exitZ, exitMap);
Database.UpdateRows("Portals" + map, "ExitMap=@6, ExitX=@3, ExitY=@4, ExitZ=@5",
"WHERE EntryX=@0 AND EntryY=@1 AND EntryZ=@2", x, y, z,
exitX, exitY, exitZ, exitMap);
}
Level lvl = LevelInfo.FindExact(map);

View File

@ -45,7 +45,7 @@ namespace MCGalaxy.Commands.Chatting {
if (args.Length == 1) {
p.Message("You need to provide either \"all\" or a number."); return;
} else if (args[1].CaselessEq("all")) {
Database.Backend.DeleteRows("Inbox" + p.name);
Database.DeleteRows("Inbox" + p.name);
p.Message("Deleted all messages.");
} else {
DeleteByID(p, args[1], entries);
@ -63,8 +63,8 @@ namespace MCGalaxy.Commands.Chatting {
p.Message("Message #{0} does not exist.", num);
} else {
string[] entry = entries[num - 1];
Database.Backend.DeleteRows("Inbox" + p.name,
"WHERE PlayerFrom=@0 AND TimeSent=@1", entry[i_from], entry[i_sent]);
Database.DeleteRows("Inbox" + p.name,
"WHERE PlayerFrom=@0 AND TimeSent=@1", entry[i_from], entry[i_sent]);
p.Message("Deleted message #{0}", num);
}
}

View File

@ -41,9 +41,9 @@ namespace MCGalaxy.Commands.Chatting {
p.Message(message);
}
Database.Backend.CreateTable("Inbox" + name, createInbox);
Database.Backend.AddRow("Inbox" + name, "PlayerFrom, TimeSent, Contents",
p.name, DateTime.Now.ToString(Database.DateFormat), message);
Database.CreateTable("Inbox" + name, createInbox);
Database.AddRow("Inbox" + name, "PlayerFrom, TimeSent, Contents",
p.name, DateTime.Now.ToString(Database.DateFormat), message);
Player target = PlayerInfo.FindExact(name);
p.Message("Message sent to {0}%S.", p.FormatNick(name));

View File

@ -43,7 +43,7 @@ namespace MCGalaxy.Commands.Maintenance {
if (args[0].CaselessEq("clear")) {
p.Message("Clearing &cALL %Sblock changes for {0}%S...", lvl.ColoredName);
if (Database.TableExists("Block" + lvl.name))
Database.Backend.DeleteTable("Block" + lvl.name);
Database.DeleteTable("Block" + lvl.name);
lvl.BlockDB.DeleteBackingFile();
p.Message("Cleared &cALL %Sblock changes for " + lvl.ColoredName);
} else if (args[0].CaselessEq("disable")) {

View File

@ -60,9 +60,9 @@ namespace MCGalaxy.Commands.Maintenance {
int tmpNum = new Random().Next(0, 10000000);
string tmpName = "-tmp" + tmpNum + "-";
Database.Backend.UpdateRows("Players", "Name=@1", "WHERE Name=@0", dst, tmpName); // PLAYERS[dst] = tmp
Database.Backend.UpdateRows("Players", "Name=@1", "WHERE Name=@0", src, dst); // PLAYERS[src] = dst
Database.Backend.UpdateRows("Players", "Name=@1", "WHERE Name=@0", tmpName, src); // PLAYERS[tmp] = src
Database.UpdateRows("Players", "Name=@1", "WHERE Name=@0", dst, tmpName); // PLAYERS[dst] = tmp
Database.UpdateRows("Players", "Name=@1", "WHERE Name=@0", src, dst); // PLAYERS[src] = dst
Database.UpdateRows("Players", "Name=@1", "WHERE Name=@0", tmpName, src); // PLAYERS[tmp] = src
}
static void SwapGroups(string src, string dst, Group srcGroup, Group dstGroup) {

View File

@ -179,8 +179,8 @@ namespace MCGalaxy.Commands.Maintenance {
static object ReadLong(IDataRecord record, object arg) { return record.GetInt64(0); }
static long GetLong(string name, string column) {
return (long)Database.Backend.ReadRows("Players", column, null, ReadLong,
"WHERE Name=@0", name);
return (long)Database.ReadRows("Players", column, null, ReadLong,
"WHERE Name=@0", name);
}
static void SetInteger(Player p, string[] args, string column, int max, Player who,

View File

@ -84,25 +84,21 @@ namespace MCGalaxy.SQL {
static object IterateExists(IDataRecord record, object arg) { return ""; }
public override bool TableExists(string table) {
ValidateTable(table);
return Database.Iterate("SHOW TABLES LIKE '" + table + "'",
null, IterateExists) != null;
}
public override List<string> AllTables() {
return Database.GetStrings("SHOW TABLES");
return GetStrings("SHOW TABLES");
}
public override List<string> ColumnNames(string table) {
ValidateTable(table);
return Database.GetStrings("DESCRIBE `" + table + "`");
Database.ValidateName(table);
return GetStrings("DESCRIBE `" + table + "`");
}
public override void RenameTable(string srcTable, string dstTable) {
ValidateTable(srcTable);
ValidateTable(dstTable);
string sql = "RENAME TABLE `" + srcTable + "` TO `" + dstTable + "`";
Database.Execute(sql, null);
public override string RenameTableSql(string srcTable, string dstTable) {
return "RENAME TABLE `" + srcTable + "` TO `" + dstTable + "`";
}
protected override void CreateTableColumns(StringBuilder sql, ColumnDesc[] columns) {
@ -148,16 +144,14 @@ namespace MCGalaxy.SQL {
w.WriteLine(");");
}
public override void AddColumn(string table, ColumnDesc col, string colAfter) {
ValidateTable(table);
public override string AddColumnSql(string table, ColumnDesc col, string colAfter) {
string sql = "ALTER TABLE `" + table + "` ADD COLUMN " + col.Column + " " + col.FormatType();
if (colAfter.Length > 0) sql += " AFTER " + colAfter;
Database.Execute(sql, null);
return sql;
}
public override void AddOrReplaceRow(string table, string columns, params object[] args) {
ValidateTable(table);
DoInsert("REPLACE INTO", table, columns, args);
public override string AddOrReplaceRowSql(string table, string columns, object[] args) {
return InsertSql("REPLACE INTO", table, columns, args);
}
}
}

View File

@ -59,14 +59,13 @@ namespace MCGalaxy.SQL {
}
public override bool TableExists(string table) {
ValidateTable(table);
return Database.CountRows("sqlite_master",
"WHERE type='table' AND name=@0", table) > 0;
}
public override List<string> AllTables() {
const string sql = "SELECT name from sqlite_master WHERE type='table'";
List<string> tables = Database.GetStrings(sql);
List<string> tables = GetStrings(sql);
// exclude sqlite built-in database tables
for (int i = tables.Count - 1; i >= 0; i--) {
@ -82,7 +81,7 @@ namespace MCGalaxy.SQL {
}
public override List<string> ColumnNames(string table) {
ValidateTable(table);
Database.ValidateName(table);
List<string> columns = new List<string>();
Database.Iterate("PRAGMA table_info(`" + table + "`)",
@ -90,11 +89,8 @@ namespace MCGalaxy.SQL {
return columns;
}
public override void RenameTable(string srcTable, string dstTable) {
ValidateTable(srcTable);
ValidateTable(dstTable);
string sql = "ALTER TABLE `" + srcTable + "` RENAME TO `" + dstTable + "`";
Database.Execute(sql, null);
public override string RenameTableSql(string srcTable, string dstTable) {
return "ALTER TABLE `" + srcTable + "` RENAME TO `" + dstTable + "`";
}
protected override void CreateTableColumns(StringBuilder sql, ColumnDesc[] columns) {
@ -124,7 +120,7 @@ namespace MCGalaxy.SQL {
public override void PrintSchema(string table, TextWriter w) {
string sql = "SELECT sql from sqlite_master WHERE tbl_name = @0 AND type = 'table'";
List<string> all = Database.GetStrings(sql + CaselessWhereSuffix, table);
List<string> all = GetStrings(sql + CaselessWhereSuffix, table);
for (int i = 0; i < all.Count; i++) {
sql = all[i].Replace(" " + table, " `" + table + "`");
@ -133,15 +129,12 @@ namespace MCGalaxy.SQL {
}
}
public override void AddColumn(string table, ColumnDesc col, string colAfter) {
ValidateTable(table);
string sql = "ALTER TABLE `" + table + "` ADD COLUMN " + col.Column + " " + col.FormatType();
Database.Execute(sql, null);
public override string AddColumnSql(string table, ColumnDesc col, string colAfter) {
return "ALTER TABLE `" + table + "` ADD COLUMN " + col.Column + " " + col.FormatType();
}
public override void AddOrReplaceRow(string table, string columns, params object[] args) {
ValidateTable(table);
DoInsert("INSERT OR REPLACE INTO", table, columns, args);
public override string AddOrReplaceRowSql(string table, string columns, object[] args) {
return InsertSql("INSERT OR REPLACE INTO", table, columns, args);
}
}

View File

@ -45,7 +45,7 @@ namespace MCGalaxy.DB {
mapName = table.Substring("Block".Length);
try {
Database.Backend.ReadRows(table, "*", null, DumpRow);
Database.ReadRows(table, "*", null, DumpRow);
WriteBuffer(true);
AppendCbdbFile();
SaveCbdbFile();
@ -55,7 +55,7 @@ namespace MCGalaxy.DB {
}
if (errorOccurred) return;
Database.Backend.DeleteTable(table);
Database.DeleteTable(table);
}
object DumpRow(IDataRecord record, object arg) {

View File

@ -50,7 +50,7 @@ namespace MCGalaxy.DB {
int i = Server.invalidIds.IndexOf(name);
if (i >= 0) ids.Add(MaxPlayerID - i);
Database.Backend.ReadRows("Players", "ID", ids, ListIds, "WHERE Name=@0", name);
Database.ReadRows("Players", "ID", ids, ListIds, "WHERE Name=@0", name);
return ids.ToArray();
}

View File

@ -27,14 +27,13 @@ namespace MCGalaxy.SQL {
/// <summary> Abstracts a SQL database management engine. </summary>
public static class Database {
public static IDatabaseBackend Backend;
public static bool TableExists(string table) { return Backend.TableExists(table); }
public const string DateFormat = "yyyy-MM-dd HH:mm:ss";
public const string DateFormat = "yyyy-MM-dd HH:mm:ss";
static object ReadInt(IDataRecord record, object arg) { return record.GetInt32(0); }
/// <summary> Counts rows in the given table. </summary>
/// <param name="modifier"> Optional SQL to filter which rows are counted. </param>
public static int CountRows(string table, string modifier = "", params object[] args) {
return (int)Backend.ReadRows(table, "COUNT(*)", null, ReadInt, modifier, args);
return (int)ReadRows(table, "COUNT(*)", null, ReadInt, modifier, args);
}
static object ReadString(IDataRecord record, object arg) { return record.GetText(0); }
@ -42,17 +41,12 @@ namespace MCGalaxy.SQL {
/// <param name="modifier"> Optional SQL to filter which rows are read. </param>
public static string ReadString(string table, string column,
string modifier = "", params object[] args) {
return (string)Backend.ReadRows(table, column, null, ReadString, modifier, args);
return (string)ReadRows(table, column, null, ReadString, modifier, args);
}
internal static object ReadList(IDataRecord record, object arg) {
((List<string>)arg).Add(record.GetText(0)); return arg;
}
internal static List<string> GetStrings(string sql, params object[] args) {
List<string> values = new List<string>();
Iterate(sql, values, ReadList, args);
return values;
}
internal static object ReadFields(IDataRecord record, object arg) {
string[] field = new string[record.FieldCount];
@ -66,11 +60,108 @@ namespace MCGalaxy.SQL {
public static List<string[]> GetRows(string table, string columns,
string modifier = "", params object[] args) {
List<string[]> fields = new List<string[]>();
Backend.ReadRows(table, columns, fields, ReadFields, modifier, args);
ReadRows(table, columns, fields, ReadFields, modifier, args);
return fields;
}
#region High level table management
/// <summary> Returns whether a table (case sensitive) exists by that name. </summary>
public static bool TableExists(string table) {
ValidateName(table);
return Backend.TableExists(table);
}
/// <summary> Creates a new table in the database (unless it already exists). </summary>
public static void CreateTable(string table, ColumnDesc[] columns) {
ValidateName(table);
string sql = Backend.CreateTableSql(table, columns);
Execute(sql, null);
}
/// <summary> Renames the source table to the given name. </summary>
public static void RenameTable(string srcTable, string dstTable) {
ValidateName(srcTable);
ValidateName(dstTable);
string sql = Backend.RenameTableSql(srcTable, dstTable);
Execute(sql, null);
}
/// <summary> Completely removes the given table. </summary>
public static void DeleteTable(string table) {
ValidateName(table);
string sql = Backend.DeleteTableSql(table);
Execute(sql, null);
}
/// <summary> Adds a new coloumn to the given table. </summary>
/// <remarks> Note colAfter is only a hint - some database backends ignore this. </remarks>
public static void AddColumn(string table, ColumnDesc col, string colAfter) {
ValidateName(table);
string sql = Backend.AddColumnSql(table, col, colAfter);
Execute(sql, null);
}
#endregion
#region High level functions
/// <summary> Inserts/Copies all the rows from the source table into the destination table. </summary>
/// <remarks> May NOT work correctly if the tables have different schema. </remarks>
public static void CopyAllRows(string srcTable, string dstTable) {
ValidateName(srcTable);
ValidateName(dstTable);
string sql = Backend.CopyAllRowsSql(srcTable, dstTable);
Execute(sql, null);
}
/// <summary> Iterates over read rows for the given table. </summary>
/// <param name="modifier"> Optional SQL to filter which rows are read,
/// return rows in a certain order, etc.</param>
public static object ReadRows(string table, string columns, object arg,
ReaderCallback callback, string modifier = "", params object[] args) {
ValidateName(table);
string sql = Backend.ReadRowsSql(table, columns, modifier);
return Iterate(sql, arg, callback, args);
}
/// <summary> Updates rows for the given table. </summary>
/// <param name="modifier"> Optional SQL to filter which rows are updated. </param>
public static void UpdateRows(string table, string columns,
string modifier = "", params object[] args) {
ValidateName(table);
string sql = Backend.UpdateRowsSql(table, columns, modifier);
Execute(sql, args);
}
/// <summary> Deletes rows for the given table. </summary>
/// <param name="modifier"> Optional SQL to filter which rows are deleted. </param>
public static void DeleteRows(string table, string modifier = "", params object[] args) {
ValidateName(table);
string sql = Backend.DeleteRowsSql(table, modifier);
Execute(sql, args);
}
/// <summary> Adds a row to the given table. </summary>
public static void AddRow(string table, string columns, params object[] args) {
ValidateName(table);
string sql = Backend.AddRowSql(table, columns, args);
Execute(sql, args);
}
/// <summary> Adds or replaces a row (same primary key) in the given table. </summary>
public static void AddOrReplaceRow(string table, string columns, params object[] args) {
ValidateName(table);
string sql = Backend.AddOrReplaceRowSql(table, columns, args);
Execute(sql, args);
}
#endregion
#region Low level functions
/// <summary> Executes an SQL command that does not return any results. </summary>
public static void Execute(string sql, params object[] args) {
Do(sql, false, null, null, args);
@ -101,6 +192,22 @@ namespace MCGalaxy.SQL {
Logger.LogError("Error executing SQL statement: " + sql, e);
return arg;
}
#endregion
internal static bool ValidNameChar(char c) {
return
c > ' ' && c != '"' && c != '%' && c != '&' &&
c != '\'' && c != '*' && c != '/' && c != ':' &&
c != '<' && c != '>' && c != '?' && c != '\\' &&
c != '`' && c != '|' && c <= '~';
}
internal static void ValidateName(string table) {
foreach (char c in table) {
if (ValidNameChar(c)) continue;
throw new ArgumentException("Invalid character in table name: " + c);
}
}
}
internal static class DatabaseExts {

View File

@ -48,6 +48,12 @@ namespace MCGalaxy.SQL {
protected internal virtual void ParseCreate(ref string cmd) { }
protected static List<string> GetStrings(string sql, params object[] args) {
List<string> values = new List<string>();
Database.Iterate(sql, values, Database.ReadList, args);
return values;
}
// == Higher level table management functions ==
@ -60,93 +66,72 @@ namespace MCGalaxy.SQL {
/// <summary> Returns a list of the column names in the given table. </summary>
public abstract List<string> ColumnNames(string table);
/// <summary> Renames the source table to the given name. </summary>
public abstract void RenameTable(string srcTable, string dstTable);
/// <summary> Returns SQL for renaming the source table to the given name. </summary>
public abstract string RenameTableSql(string srcTable, string dstTable);
/// <summary> Creates a new table in the database (unless it already exists). </summary>
public virtual void CreateTable(string table, ColumnDesc[] columns) {
ValidateTable(table);
/// <summary> Returns SQL for creating a new table (unless it already exists). </summary>
public virtual string CreateTableSql(string table, ColumnDesc[] columns) {
StringBuilder sql = new StringBuilder();
sql.AppendLine("CREATE TABLE if not exists `" + table + "` (");
CreateTableColumns(sql, columns);
sql.AppendLine(");");
Database.Execute(sql.ToString(), null);
return sql.ToString();
}
protected abstract void CreateTableColumns(StringBuilder sql, ColumnDesc[] columns);
/// <summary> Completely removes the given table. </summary>
public virtual void DeleteTable(string table) {
ValidateTable(table);
string sql = "DROP TABLE `" + table + "`";
Database.Execute(sql, null);
/// <summary> Returns SQL for completely removing the given table. </summary>
public virtual string DeleteTableSql(string table) {
return "DROP TABLE `" + table + "`";
}
/// <summary> Prints/dumps the table schema of the given table. </summary>
public abstract void PrintSchema(string table, TextWriter w);
// == Higher level column functions ==
/// <summary> Adds a new coloumn to the given table. </summary>
/// <summary> Returns SQL for adding a new coloumn to the given table. </summary>
/// <remarks> Note colAfter is only a hint - some database backends ignore this. </remarks>
public abstract void AddColumn(string table, ColumnDesc col, string colAfter);
public abstract string AddColumnSql(string table, ColumnDesc col, string colAfter);
// == Higher level functions ==
/// <summary> Inserts/Copies all the rows from the source table into the destination table. </summary>
/// <remarks> Note: This may work incorrectly if the tables have different schema. </remarks>
public virtual void CopyAllRows(string srcTable, string dstTable) {
ValidateTable(srcTable);
ValidateTable(dstTable);
string sql = "INSERT INTO `" + dstTable + "` SELECT * FROM `" + srcTable + "`";
Database.Execute(sql, null);
/// <summary> Returns SQL for copying all the rows from the source table into the destination table. </summary>
public virtual string CopyAllRowsSql(string srcTable, string dstTable) {
return "INSERT INTO `" + dstTable + "` SELECT * FROM `" + srcTable + "`";
}
/// <summary> Iterates over read rows for the given table. </summary>
/// <remarks> modifier is optional SQL which can be used to read only certain rows,
/// return rows in a certain order, etc.</remarks>
public virtual object ReadRows(string table, string columns, object arg,
ReaderCallback callback, string modifier = "", params object[] args) {
ValidateTable(table);
/// <summary> Returns SQL for reading rows from the given table. </summary>
public virtual string ReadRowsSql(string table, string columns, string modifier) {
string sql = "SELECT " + columns + " FROM `" + table + "`";
if (modifier.Length > 0) sql += " " + modifier;
return Database.Iterate(sql, arg, callback, args);
return sql;
}
/// <summary> Updates rows for the given table. </summary>
/// <remarks> modifier is optional SQL which can be used to update only certain rows.</remarks>
public virtual void UpdateRows(string table, string columns,
string modifier = "", params object[] args) {
ValidateTable(table);
/// <summary> Returns SQL for updating rows for the given table. </summary>
public virtual string UpdateRowsSql(string table, string columns, string modifier) {
string sql = "UPDATE `" + table + "` SET " + columns;
if (modifier.Length > 0) sql += " " + modifier;
Database.Execute(sql, args);
return sql;
}
/// <summary> Deletes rows for the given table. </summary>
/// <remarks> modifier is optional SQL which can be used to delete only certain rows.</remarks>
public virtual void DeleteRows(string table, string modifier = "", params object[] args) {
ValidateTable(table);
/// <summary> Returns SQL for deleting rows for the given table. </summary>
public virtual string DeleteRowsSql(string table, string modifier) {
string sql = "DELETE FROM `" + table + "`";
if (modifier.Length > 0) sql += " " + modifier;
Database.Execute(sql, args);
return sql;
}
/// <summary> Adds a row to the given table. </summary>
public virtual void AddRow(string table, string columns, params object[] args) {
ValidateTable(table);
DoInsert("INSERT INTO", table, columns, args);
/// <summary> Returns SQL for adding a row to the given table. </summary>
public virtual string AddRowSql(string table, string columns, object[] args) {
return InsertSql("INSERT INTO", table, columns, args);
}
/// <summary> Adds or replaces a row (same primary key) in the given table. </summary>
public abstract void AddOrReplaceRow(string table, string columns, params object[] args);
/// <summary> Returns SQL for adding or replacing a row (same primary key) in the given table. </summary>
public abstract string AddOrReplaceRowSql(string table, string columns, object[] args);
protected void DoInsert(string command, string table,
string columns, params object[] args) {
StringBuilder sql = new StringBuilder(command);
protected string InsertSql(string cmd, string table, string columns, object[] args) {
StringBuilder sql = new StringBuilder(cmd);
sql.Append(" `").Append(table).Append("` ");
sql.Append('(').Append(columns).Append(')');
@ -157,22 +142,7 @@ namespace MCGalaxy.SQL {
if (i < args.Length - 1) sql.Append(", ");
else sql.Append(")");
}
Database.Execute(sql.ToString(), args);
}
internal static bool ValidNameChar(char c) {
return
c > ' ' && c != '"' && c != '%' && c != '&' &&
c != '\'' && c != '*' && c != '/' && c != ':' &&
c != '<' && c != '>' && c != '?' && c != '\\' &&
c != '`' && c != '|' && c <= '~';
}
protected static void ValidateTable(string name) {
foreach (char c in name) {
if (ValidNameChar(c)) continue;
throw new ArgumentException("Invalid character in table name: " + c);
}
return sql.ToString();
}
}
}

View File

@ -94,7 +94,7 @@ namespace MCGalaxy.DB {
public static void Update(string name, string column, string value) {
Database.Backend.UpdateRows("Players", column + "=@1", "WHERE Name=@0", name, value);
Database.UpdateRows("Players", column + "=@1", "WHERE Name=@0", name, value);
}
public static string FindColor(Player p) {
@ -138,9 +138,9 @@ namespace MCGalaxy.DB {
static void MatchMulti(string name, string columns, object arg, ReaderCallback callback) {
string suffix = Database.Backend.CaselessLikeSuffix;
Database.Backend.ReadRows("Players", columns, arg, callback,
"WHERE Name LIKE @0 ESCAPE '#' LIMIT 21" + suffix,
"%" + name.Replace("_", "#_") + "%");
Database.ReadRows("Players", columns, arg, callback,
"WHERE Name LIKE @0 ESCAPE '#' LIMIT 21" + suffix,
"%" + name.Replace("_", "#_") + "%");
}
}
}

View File

@ -59,11 +59,11 @@ namespace MCGalaxy.DB {
p.TimesVisited = 1;
string now = DateTime.Now.ToString(Database.DateFormat);
Database.Backend.AddRow("Players", "Name, IP, FirstLogin, LastLogin, totalLogin, Title, " +
"totalDeaths, Money, totalBlocks, totalKicked, Messages, TimeSpent",
p.name, p.ip, now, now, 1, "", 0, 0, 0, 0, 0, (long)p.TotalTime.TotalSeconds);
Database.AddRow("Players", "Name, IP, FirstLogin, LastLogin, totalLogin, Title, " +
"totalDeaths, Money, totalBlocks, totalKicked, Messages, TimeSpent",
p.name, p.ip, now, now, 1, "", 0, 0, 0, 0, 0, (long)p.TotalTime.TotalSeconds);
object id = Database.Backend.ReadRows("Players", "ID", null, ReadID, "WHERE Name=@0", p.name);
object id = Database.ReadRows("Players", "ID", null, ReadID, "WHERE Name=@0", p.name);
if (id != null) {
p.DatabaseID = (int)id;
} else {

View File

@ -31,7 +31,7 @@ namespace MCGalaxy.SQL {
gottenRows = false;
this.sql = sql;
this.table = table;
Database.Backend.ReadRows(table, "*", null, DumpRow);
Database.ReadRows(table, "*", null, DumpRow);
if (!gottenRows) {
sql.WriteLine("-- No data in table `{0}`!", table);

View File

@ -42,11 +42,11 @@ namespace MCGalaxy.Eco {
}
public static void LoadDatabase() {
Database.Backend.CreateTable("Economy", createEconomy);
Database.CreateTable("Economy", createEconomy);
// money used to be in the Economy table, move it back to the Players table
List<EcoStats> outdated = new List<EcoStats>();
Database.Backend.ReadRows("Economy", "*", outdated, ListOld, "WHERE money > 0");
Database.ReadRows("Economy", "*", outdated, ListOld, "WHERE money > 0");
if (outdated.Count == 0) return;
Logger.Log(LogType.SystemActivity, "Upgrading economy stats..");
@ -73,9 +73,9 @@ namespace MCGalaxy.Eco {
}
public static void UpdateStats(EcoStats stats) {
Database.Backend.AddOrReplaceRow("Economy", "player, money, total, purchase, payment, salary, fine",
stats.Player, 0, stats.TotalSpent, stats.Purchase,
stats.Payment, stats.Salary, stats.Fine);
Database.AddOrReplaceRow("Economy", "player, money, total, purchase, payment, salary, fine",
stats.Player, 0, stats.TotalSpent, stats.Purchase,
stats.Payment, stats.Salary, stats.Fine);
}
static EcoStats ParseStats(IDataRecord record) {
@ -100,8 +100,8 @@ namespace MCGalaxy.Eco {
public static EcoStats RetrieveStats(string name) {
EcoStats stats = default(EcoStats);
stats.Player = name;
return (EcoStats)Database.Backend.ReadRows("Economy", "*", stats, ReadStats,
"WHERE player=@0", name);
return (EcoStats)Database.ReadRows("Economy", "*", stats, ReadStats,
"WHERE player=@0", name);
}
}
}

View File

@ -45,8 +45,8 @@ namespace MCGalaxy.Games {
static CtfStats LoadStats(string name) {
CtfStats stats = default(CtfStats);
return (CtfStats)Database.Backend.ReadRows("CTF", "*", stats,
ReadStats, "WHERE Name=@0", name);
return (CtfStats)Database.ReadRows("CTF", "*", stats,
ReadStats, "WHERE Name=@0", name);
}
protected override void SaveStats(Player p) {
@ -55,11 +55,11 @@ namespace MCGalaxy.Games {
int count = Database.CountRows("CTF", "WHERE Name=@0", p.name);
if (count == 0) {
Database.Backend.AddRow("CTF", "Points, Captures, tags, Name",
data.Points, data.Captures, data.Tags, p.name);
Database.AddRow("CTF", "Points, Captures, tags, Name",
data.Points, data.Captures, data.Tags, p.name);
} else {
Database.Backend.UpdateRows("CTF", "Points=@0, Captures=@1, tags=@2", "WHERE Name=@3",
data.Points, data.Captures, data.Tags, p.name);
Database.UpdateRows("CTF", "Points=@0, Captures=@1, tags=@2", "WHERE Name=@3",
data.Points, data.Captures, data.Tags, p.name);
}
}
}

View File

@ -113,7 +113,7 @@ namespace MCGalaxy.Games {
Red.RespawnFlag(Map);
ResetTeams();
Database.Backend.CreateTable("CTF", createSyntax);
Database.CreateTable("CTF", createSyntax);
}
protected override void EndGame() {

View File

@ -114,8 +114,8 @@ namespace MCGalaxy.Games {
static ZombieStats LoadStats(string name) {
ZombieStats stats = default(ZombieStats);
return (ZombieStats)Database.Backend.ReadRows("ZombieStats", "*", stats,
ReadStats, "WHERE Name=@0", name);
return (ZombieStats)Database.ReadRows("ZombieStats", "*", stats,
ReadStats, "WHERE Name=@0", name);
}
protected override void SaveStats(Player p) {
@ -124,13 +124,13 @@ namespace MCGalaxy.Games {
int count = Database.CountRows("ZombieStats", "WHERE Name=@0", p.name);
if (count == 0) {
Database.Backend.AddRow("ZombieStats", "TotalRounds, MaxRounds, TotalInfected, MaxInfected, Name",
data.TotalRoundsSurvived, data.MaxRoundsSurvived,
data.TotalInfected, data.MaxInfected, p.name);
Database.AddRow("ZombieStats", "TotalRounds, MaxRounds, TotalInfected, MaxInfected, Name",
data.TotalRoundsSurvived, data.MaxRoundsSurvived,
data.TotalInfected, data.MaxInfected, p.name);
} else {
Database.Backend.UpdateRows("ZombieStats", "TotalRounds=@0, MaxRounds=@1, TotalInfected=@2, MaxInfected=@3",
"WHERE Name=@4", data.TotalRoundsSurvived, data.MaxRoundsSurvived,
data.TotalInfected, data.MaxInfected, p.name);
Database.UpdateRows("ZombieStats", "TotalRounds=@0, MaxRounds=@1, TotalInfected=@2, MaxInfected=@3",
"WHERE Name=@4", data.TotalRoundsSurvived, data.MaxRoundsSurvived,
data.TotalInfected, data.MaxInfected, p.name);
}
}
}

View File

@ -126,7 +126,7 @@ namespace MCGalaxy.Games {
}
protected override void StartGame() {
Database.Backend.CreateTable("ZombieStats", createSyntax);
Database.CreateTable("ZombieStats", createSyntax);
HookStats();
}

View File

@ -94,7 +94,7 @@ namespace MCGalaxy {
static void RenameDatabaseTables(Player p, string src, string dst) {
if (Database.TableExists("Block" + src)) {
Database.Backend.RenameTable("Block" + src, "Block" + dst);
Database.RenameTable("Block" + src, "Block" + dst);
}
object srcLocker = ThreadSafeCache.DBCache.GetLocker(src);
object dstLocker = ThreadSafeCache.DBCache.GetLocker(dst);
@ -106,7 +106,7 @@ namespace MCGalaxy {
MessageBlock.MoveAll(src, dst);
if (Database.TableExists("Zone" + src)) {
Database.Backend.RenameTable("Zone" + src, "Zone" + dst);
Database.RenameTable("Zone" + src, "Zone" + dst);
}
}
@ -115,8 +115,8 @@ namespace MCGalaxy {
foreach (string table in tables) {
if (!table.StartsWith("Portals")) continue;
Database.Backend.UpdateRows(table, "ExitMap=@1",
"WHERE ExitMap=@0", src, dst);
Database.UpdateRows(table, "ExitMap=@1",
"WHERE ExitMap=@0", src, dst);
}
}
@ -176,7 +176,7 @@ namespace MCGalaxy {
static void DeleteDatabaseTables(string map) {
if (Database.TableExists("Block" + map)) {
Database.Backend.DeleteTable("Block" + map);
Database.DeleteTable("Block" + map);
}
object locker = ThreadSafeCache.DBCache.GetLocker(map);
@ -185,7 +185,7 @@ namespace MCGalaxy {
MessageBlock.DeleteAll(map);
if (Database.TableExists("Zone" + map)) {
Database.Backend.DeleteTable("Zone" + map);
Database.DeleteTable("Zone" + map);
}
}
}

View File

@ -60,7 +60,7 @@ namespace MCGalaxy {
if (!Database.TableExists("Zone" + map)) return;
List<Zone> zones = new List<Zone>();
Database.Backend.ReadRows("Zone" + map, "*", zones, ListZones);
Database.ReadRows("Zone" + map, "*", zones, ListZones);
bool changedPerbuild = false;
for (int i = 0; i < zones.Count; i++) {
@ -86,7 +86,7 @@ namespace MCGalaxy {
if (changedPerbuild) level.SaveSettings();
if (level.Zones.Count > 0 && !level.Save(true)) return;
Database.Backend.DeleteTable("Zone" + map);
Database.DeleteTable("Zone" + map);
Logger.Log(LogType.SystemActivity, "Upgraded zones for map " + map);
}

View File

@ -149,7 +149,7 @@ namespace MCGalaxy {
public static bool ValidName(string map) {
foreach (char c in map) {
if (!IDatabaseBackend.ValidNameChar(c)) return false;
if (!Database.ValidNameChar(c)) return false;
}
return true;
}

View File

@ -677,8 +677,8 @@ namespace MCGalaxy {
try { //opstats patch (since 5.5.11)
if (Server.Opstats.CaselessContains(cmd) || (cmd.CaselessEq("review") && message.CaselessEq("next") && Server.reviewlist.Count > 0)) {
Database.Backend.AddRow("Opstats", "Time, Name, Cmd, Cmdmsg",
DateTime.Now.ToString(Database.DateFormat), name, cmd, message);
Database.AddRow("Opstats", "Time, Name, Cmd, Cmdmsg",
DateTime.Now.ToString(Database.DateFormat), name, cmd, message);
}
} catch { }

View File

@ -209,9 +209,8 @@ namespace MCGalaxy {
}
void GetPlayerStats() {
object raw = Database.Backend.ReadRows("Players", "*",
null, PlayerData.Read,
"WHERE Name=@0", name);
object raw = Database.ReadRows("Players", "*", null, PlayerData.Read,
"WHERE Name=@0", name);
if (raw == null) {
PlayerData.Create(this);
Chat.MessageFrom(this, "λNICK %Shas connected for the first time!");

View File

@ -164,11 +164,11 @@ namespace MCGalaxy {
if (!gotSQLData) return;
long blocks = PlayerData.Pack(TotalPlaced, TotalModified);
long drawn = PlayerData.Pack(TotalDeleted, TotalDrawn);
Database.Backend.UpdateRows("Players", "IP=@0, LastLogin=@1, totalLogin=@2, totalDeaths=@3, Money=@4, " +
"totalBlocks=@5, totalCuboided=@6, totalKicked=@7, TimeSpent=@8, Messages=@9", "WHERE Name=@10",
ip, LastLogin.ToString(Database.DateFormat),
TimesVisited, TimesDied, money, blocks,
drawn, TimesBeenKicked, (long)TotalTime.TotalSeconds, TotalMessagesSent, name);
Database.UpdateRows("Players", "IP=@0, LastLogin=@1, totalLogin=@2, totalDeaths=@3, Money=@4, " +
"totalBlocks=@5, totalCuboided=@6, totalKicked=@7, TimeSpent=@8, Messages=@9", "WHERE Name=@10",
ip, LastLogin.ToString(Database.DateFormat),
TimesVisited, TimesDied, money, blocks,
drawn, TimesBeenKicked, (long)TotalTime.TotalSeconds, TotalMessagesSent, name);
}
public bool CanUse(Command cmd) { return group.Commands.Contains(cmd); }

View File

@ -95,9 +95,8 @@ namespace MCGalaxy {
public static PlayerData FindData(string name) {
string suffix = Database.Backend.CaselessWhereSuffix;
object raw = Database.Backend.ReadRows("Players", "*",
null, PlayerData.Read,
"WHERE Name=@0" + suffix, name);
object raw = Database.ReadRows("Players", "*", null, PlayerData.Read,
"WHERE Name=@0" + suffix, name);
return (PlayerData)raw;
}
@ -130,7 +129,7 @@ namespace MCGalaxy {
/// <remarks> This is current IP for online players, last IP for offline players from the database. </remarks>
public static List<string> FindAccounts(string ip) {
List<string> names = new List<string>();
Database.Backend.ReadRows("Players", "Name", names, ReadAccounts, "WHERE IP=@0", ip);
Database.ReadRows("Players", "Name", names, ReadAccounts, "WHERE IP=@0", ip);
// TODO: should we instead do save() when the player logs in
// by checking online players we avoid a DB write though

View File

@ -199,7 +199,7 @@ namespace MCGalaxy {
List<string> tables = Database.Backend.AllTables();
foreach (string table in tables) {
Database.Backend.DeleteTable(table);
Database.DeleteTable(table);
}
ImportSql(sql);
}

View File

@ -62,8 +62,8 @@ namespace MCGalaxy {
return;
}
Database.Backend.CreateTable("Opstats", createOpstats);
Database.Backend.CreateTable("Players", createPlayers);
Database.CreateTable("Opstats", createOpstats);
Database.CreateTable("Players", createPlayers);
//since 5.5.11 we are cleaning up the table Playercmds
//if Playercmds exists copy-filter to Opstats and remove Playercmds
@ -72,26 +72,26 @@ namespace MCGalaxy {
foreach (string cmd in Server.Opstats)
Database.Execute(string.Format(sql, "cmd = '" + cmd + "'"));
Database.Execute(string.Format(sql, "cmd = 'review' AND cmdmsg = 'next'"));
Database.Backend.DeleteTable("Playercmds");
Database.DeleteTable("Playercmds");
}
List<string> columns = Database.Backend.ColumnNames("Players");
if (columns.Count == 0) return;
if (!columns.CaselessContains("Color")) {
Database.Backend.AddColumn("Players", new ColumnDesc("color", ColumnType.VarChar, 6), "totalKicked");
Database.AddColumn("Players", new ColumnDesc("color", ColumnType.VarChar, 6), "totalKicked");
}
if (!columns.CaselessContains("Title_Color")) {
Database.Backend.AddColumn("Players", new ColumnDesc("title_color", ColumnType.VarChar, 6), "color");
Database.AddColumn("Players", new ColumnDesc("title_color", ColumnType.VarChar, 6), "color");
}
if (!columns.CaselessContains("TimeSpent")) {
Database.Backend.AddColumn("Players", new ColumnDesc("TimeSpent", ColumnType.VarChar, 20), "totalKicked");
Database.AddColumn("Players", new ColumnDesc("TimeSpent", ColumnType.VarChar, 20), "totalKicked");
}
if (!columns.CaselessContains("TotalCuboided")) {
Database.Backend.AddColumn("Players", new ColumnDesc("totalCuboided", ColumnType.Int64), "totalBlocks");
Database.AddColumn("Players", new ColumnDesc("totalCuboided", ColumnType.Int64), "totalBlocks");
}
if (!columns.CaselessContains("Messages")) {
Database.Backend.AddColumn("Players", new ColumnDesc("Messages", ColumnType.UInt24), "title_color");
Database.AddColumn("Players", new ColumnDesc("Messages", ColumnType.UInt24), "title_color");
}
}
}

View File

@ -181,7 +181,7 @@ namespace MCGalaxy.Tasks {
static void DumpPlayerTimeSpents() {
playerIds = new List<int>();
playerSeconds = new List<long>();
Database.Backend.ReadRows("Players", "ID,TimeSpent", null, ReadTimeSpent);
Database.ReadRows("Players", "ID,TimeSpent", null, ReadTimeSpent);
}
static object ReadTimeSpent(IDataRecord record, object arg) {