From dcc1e2462c731e07e1790d6176eeaecc29868865 Mon Sep 17 00:00:00 2001 From: UnknownShadow200 Date: Thu, 30 Jun 2016 10:18:12 +1000 Subject: [PATCH] Modularise Database.cs --- Commands/building/CmdPortal.cs | 26 ++-- Commands/other/CmdServer.cs | 20 ++- Database/Backup.cs | 256 +++++++++++++++------------------ 3 files changed, 139 insertions(+), 163 deletions(-) diff --git a/Commands/building/CmdPortal.cs b/Commands/building/CmdPortal.cs index fe4e6c9dd..4d17f9b60 100644 --- a/Commands/building/CmdPortal.cs +++ b/Commands/building/CmdPortal.cs @@ -49,6 +49,7 @@ namespace MCGalaxy.Commands.Building { else if (block == "water") { data.type = Block.water_portal; } else if (block == "lava") { data.type = Block.lava_portal; } else if (block == "show") { ShowPortals(p); return; } + else if (block == "list") { ListPortals(p); return; } else { Help(p); return; } Player.Message(p, "Place an &aEntry block %Sfor the portal"); @@ -94,13 +95,10 @@ namespace MCGalaxy.Commands.Building { DataTable Portals = Database.fillData("SELECT * FROM `Portals" + pos.mapName + "` WHERE EntryX=" + (int)pos.x + " AND EntryY=" + (int)pos.y + " AND EntryZ=" + (int)pos.z); Portals.Dispose(); - if (Portals.Rows.Count == 0) - {//safe against SQL injections because no user input is given here + if (Portals.Rows.Count == 0) {//safe against SQL injections because no user input is given here Database.executeQuery("INSERT INTO `Portals" + pos.mapName + "` (EntryX, EntryY, EntryZ, ExitMap, ExitX, ExitY, ExitZ) VALUES (" + (int)pos.x + ", " + (int)pos.y + ", " + (int)pos.z + ", '" + p.level.name + "', " + (int)x + ", " + (int)y + ", " + (int)z + ")"); - } - else - {//safe against SQL injections because no user input is given here + } else {//safe against SQL injections because no user input is given here Database.executeQuery("UPDATE `Portals" + pos.mapName + "` SET ExitMap='" + p.level.name + "', ExitX=" + (int)x + ", ExitY=" + (int)y + ", ExitZ=" + (int)z + " WHERE EntryX=" + (int)pos.x + " AND EntryY=" + (int)pos.y + " AND EntryZ=" + (int)pos.z); } @@ -127,8 +125,7 @@ namespace MCGalaxy.Commands.Building { DataTable Portals = Database.fillData("SELECT * FROM `Portals" + p.level.name + "`"); if (p.showPortals) { - for (int i = 0; i < Portals.Rows.Count; i++) { - DataRow row = Portals.Rows[i]; + foreach (DataRow row in Portals.Rows) { if (row["ExitMap"].ToString() == p.level.name) p.SendBlockchange(U16(row["ExitX"]), U16(row["ExitY"]), U16(row["ExitZ"]), Block.red); p.SendBlockchange(U16(row["EntryX"]), U16(row["EntryY"]), U16(row["EntryZ"]), Block.green); @@ -136,8 +133,7 @@ namespace MCGalaxy.Commands.Building { Player.Message(p, "Now showing &a" + Portals.Rows.Count + " %Sportals."); } else { - for (int i = 0; i < Portals.Rows.Count; i++) { - DataRow row = Portals.Rows[i]; + foreach (DataRow row in Portals.Rows) { if (row["ExitMap"].ToString() == p.level.name) p.RevertBlock(U16(row["ExitX"]), U16(row["ExitY"]), U16(row["ExitZ"])); p.RevertBlock(U16(row["EntryX"]), U16(row["EntryY"]), U16(row["EntryZ"])); @@ -147,6 +143,18 @@ namespace MCGalaxy.Commands.Building { Portals.Dispose(); } + void ListPortals(Player p) { + //safe against SQL injections because no user input is given here + DataTable Portals = Database.fillData("SELECT * FROM `Portals" + p.level.name + "`"); + const string format = "({0},{1},{2}) to ({3},{4},{5}) on {6}"; + foreach (DataRow row in Portals.Rows) { + Player.Message(p, format, U16(row["EntryX"]), U16(row["EntryY"]), U16(row["EntryZ"]), + U16(row["ExitX"]), U16(row["ExitY"]), U16(row["ExitZ"]), row["ExitMap"]); + } + Player.Message(p, "{0} portals in total.", Portals.Rows.Count); + Portals.Dispose(); + } + static ushort U16(object x) { return Convert.ToUInt16(x); } public override void Help(Player p) { diff --git a/Commands/other/CmdServer.cs b/Commands/other/CmdServer.cs index 1b84575db..c49778616 100644 --- a/Commands/other/CmdServer.cs +++ b/Commands/other/CmdServer.cs @@ -36,9 +36,6 @@ namespace MCGalaxy.Commands { switch (message) { - case "": // To prevent '/server' from causing an error message - Help(p); - break; case "restart": case "update": case "shutdown": @@ -92,7 +89,7 @@ namespace MCGalaxy.Commands // Also important to save everything to a .zip file (Though we can rename the extention.) // When backing up, one option is to save all non-main program files. // This means all folders, and files in these folders. - Player.Message(p, "Server backup (Everything): Started.\n\tPlease wait while backup finishes."); + Player.Message(p, "Server backup (Everything): Started. Please wait while backup finishes."); Save(true, p); break; case "backup db": @@ -102,14 +99,14 @@ namespace MCGalaxy.Commands // Also important to save everything to a .zip file (Though we can rename the extention.) // When backing up, one option is to save all non-main program files. // This means all folders, and files in these folders. - Player.Message(p, "Server backup (Database): Started.\n\tPlease wait while backup finishes."); + Player.Message(p, "Server backup (Database): Started. Please wait while backup finishes."); Save(false, true, p); break; case "backup allbutdb": // Important to save everything to a .zip file (Though we can rename the extention.) // When backing up, one option is to save all non-main program files. // This means all folders, and files in these folders. - Player.Message(p, "Server backup (Everything but Database): Started.\n\tPlease wait while backup finishes."); + Player.Message(p, "Server backup (Everything but Database): Started. Please wait while backup finishes."); Save(false, p); break; case "restore": @@ -122,11 +119,10 @@ namespace MCGalaxy.Commands extract.Start(p); break; default: - Player.Message(p, "/server " + message + " is not currently implemented."); - goto case ""; - //case "help": - // Help(p); - // break; + if (message != "") + Player.Message(p, "/server " + message + " is not currently implemented."); + Help(p); + break; } } @@ -265,7 +261,7 @@ namespace MCGalaxy.Commands private static void SaveDatabase(string filename) { using (StreamWriter sql = new StreamWriter(filename)) - Database.CopyDatabase(sql); + Database.BackupDatabase(sql); } private static List GetAllFiles(DirectoryInfo currDir, Uri baseUri) diff --git a/Database/Backup.cs b/Database/Backup.cs index c7f4d6bdc..bd2275e94 100644 --- a/Database/Backup.cs +++ b/Database/Backup.cs @@ -26,7 +26,7 @@ namespace MCGalaxy.SQL { public static partial class Database { - public static void CopyDatabase(StreamWriter sql) { + public static void BackupDatabase(StreamWriter sql) { //We technically know all tables in the DB... But since this is MySQL, we can also get them all with a MySQL command //So we show the tables, and store the result. //Also output information data (Same format as phpMyAdmin's dump) @@ -41,153 +41,125 @@ namespace MCGalaxy.SQL { sql.WriteLine("-- Generation Time: {0} at {1}", DateTime.Now.Date, DateTime.Now.TimeOfDay); sql.WriteLine("-- MCGalaxy Version: {0}", Server.Version); sql.WriteLine(); - //Extra stuff goes here sql.WriteLine(); - //database here - List sqlTables = (Database.getTables()); + + List sqlTables = Database.getTables(); foreach (string tableName in sqlTables) - { - //For each table, we iterate through all rows, (and save them) - sql.WriteLine("-- --------------------------------------------------------"); - sql.WriteLine(); - sql.WriteLine("--"); - sql.WriteLine("-- Table structure for table `{0}`", tableName); - sql.WriteLine("--"); - sql.WriteLine(); - List tableSchema = new List(); - if (Server.useMySQL) - { - string[] rowParams; - string pri; - sql.WriteLine("CREATE TABLE IF NOT EXISTS `{0}` (", tableName); - using (DataTable tableRowSchema = Database.fillData("DESCRIBE " + tableName)) - { - rowParams = new string[tableRowSchema.Columns.Count]; - pri = ""; - foreach (DataRow row in tableRowSchema.Rows) - { - //Save the info contained to file - List tmp = new List(); - for (int col = 0; col < tableRowSchema.Columns.Count; col++) - { - tmp.Add(row.Field(col)); - }// end:for(col) - rowParams = tmp.ToArray(); - rowParams[2] = (rowParams[2].ToLower().Equals("no") ? "NOT " : "DEFAULT ") + "NULL"; - pri += (rowParams[3].ToLower().Equals("pri") ? rowParams[0] + ";" : ""); - sql.WriteLine("`{0}` {1} {2}" + (rowParams[5].Equals("") ? "" : " {5}") + (pri.Equals("") && row == tableRowSchema.Rows[tableRowSchema.Rows.Count - 1] ? "" : ","), rowParams); - tableSchema.Add(rowParams); - }// end:foreach(DataRow row) - } - if (!pri.Equals("")) - { - string[] tmp = pri.Substring(0, pri.Length - 1).Split(';'); - sql.Write("PRIMARY KEY (`"); - foreach (string prim in tmp) - { - sql.Write(prim); - sql.Write("`" + (tmp[tmp.Count() - 1].Equals(prim) ? ")" : ", `")); - } - } /*else { - sql.Flush(); - sql.BaseStream.Seek(-3, SeekOrigin.Current); - }*/ - sql.WriteLine(");"); - } - else - { - using (DataTable tableSQL = Database.fillData("SELECT sql FROM" + - " (SELECT * FROM sqlite_master UNION ALL" + - " SELECT * FROM sqlite_temp_master)" + - "WHERE tbl_name LIKE '" + tableName + "'" + - " AND type!='meta' AND sql NOT NULL AND name NOT LIKE 'sqlite_%'" + - "ORDER BY substr(type,2,1), name")) - { - //just print out the data in the table. - foreach (DataRow row in tableSQL.Rows) - { - string tableSQLString = row.Field(0); - sql.WriteLine(tableSQLString.Replace(" " + tableName, " `" + tableName + "`").Replace("CREATE TABLE `" + tableName + "`", "CREATE TABLE IF NOT EXISTS `" + tableName + "`") + ";"); - //We parse this ourselves to find the actual types. - tableSchema = getSchema(tableSQLString); - - } - } - } - sql.WriteLine(); - using (DataTable tableRowData = Database.fillData("SELECT * FROM `" + tableName + "`")) - { - if (tableRowData.Rows.Count > 0) - { - sql.WriteLine("--"); - sql.WriteLine("-- Dumping data for table `{0}`", tableName); - sql.WriteLine("--"); - sql.WriteLine(); - List allCols = new List(); - foreach (DataColumn col in tableRowData.Columns) - { - allCols.Add(col); - } - foreach (DataRow row in tableRowData.Rows) - { //We rely on the correct datatype being given here. - sql.WriteLine(); - sql.Write("INSERT INTO `{0}` (`", tableName); - foreach (string[] rParams in tableSchema) - { - sql.Write(rParams[0]); - sql.Write((tableSchema.ElementAt(tableSchema.Count() - 1).Equals(rParams) ? "`) VALUES" : "`, `")); - } - //Save the info contained to file - sql.WriteLine(); - sql.Write("("); - for (int col = 0; col < row.ItemArray.Length; col++) - { - //The values themselves can be integers or strings, or null - Type eleType = allCols[col].DataType; - if (row.IsNull(col)) - { - sql.Write("NULL"); - - } - else if (eleType.Name.Equals("DateTime")) - { // special format - DateTime dt = row.Field(col); - sql.Write("'{0:yyyy-MM-dd HH:mm:ss.ffff}'", dt); - - } - else if (eleType.Name.Equals("Boolean")) - { - sql.Write(row.Field(col) ? "1" : "0"); - - } - else if (eleType.Name.Equals("String")) - { // Requires '' - sql.Write("'{0}'", row.Field(col)); - - } - else - { - sql.Write(row.Field(col)); // We assume all other data is left as-is - //This includes numbers, blobs, etc. (As well as objects, but we don't save them into the database) - - } - sql.Write((col < row.ItemArray.Length - 1 ? ", " : ");")); - }// end:for(col) - - }// end:foreach(DataRow row) - } - else - { - sql.WriteLine("-- No data in table `{0}`!", tableName); - } + BackupTable(tableName, sql); + } + + static void BackupTable(string tableName, StreamWriter sql) { + //For each table, we iterate through all rows, (and save them) + sql.WriteLine("-- --------------------------------------------------------"); + sql.WriteLine(); + sql.WriteLine("--"); + sql.WriteLine("-- Table structure for table `{0}`", tableName); + sql.WriteLine("--"); + sql.WriteLine(); + List tableSchema = WriteTableSchema(tableName, sql); + + using (DataTable data = Database.fillData("SELECT * FROM `" + tableName + "`")) { + if (data.Rows.Count == 0) { + sql.WriteLine("-- No data in table `{0}`!", tableName); sql.WriteLine(); + return; } + + sql.WriteLine("--"); + sql.WriteLine("-- Dumping data for table `{0}`", tableName); + sql.WriteLine("--"); + sql.WriteLine(); + List allCols = new List(); + foreach (DataColumn col in data.Columns) + allCols.Add(col); + + foreach (DataRow row in data.Rows) { //We rely on the correct datatype being given here. + sql.WriteLine(); + sql.Write("INSERT INTO `{0}` (`", tableName); + foreach (string[] rParams in tableSchema) { + sql.Write(rParams[0]); + sql.Write((tableSchema[tableSchema.Count - 1].Equals(rParams) ? "`) VALUES" : "`, `")); + } - }// end:foreach(DataRow sqlTablesRow) + sql.WriteLine(); + sql.Write("("); + for (int col = 0; col < row.ItemArray.Length; col++) { + //The values themselves can be integers or strings, or null + Type eleType = allCols[col].DataType; + if (row.IsNull(col)) { + sql.Write("NULL"); + } else if (eleType.Name.Equals("DateTime")) { // special format + DateTime dt = row.Field(col); + sql.Write("'{0:yyyy-MM-dd HH:mm:ss.ffff}'", dt); + } else if (eleType.Name.Equals("Boolean")) { + sql.Write(row.Field(col) ? "1" : "0"); + } else if (eleType.Name.Equals("String")) { // Requires '' + sql.Write("'{0}'", row.Field(col)); + } else { + sql.Write(row.Field(col)); // We assume all other data is left as-is + //This includes numbers, blobs, etc. (As well as objects, but we don't save them into the database) + } + sql.Write((col < row.ItemArray.Length - 1 ? ", " : ");")); + } + } + sql.WriteLine(); + } + } + + static List WriteTableSchema(string tableName, StreamWriter sql) { + List tableSchema = new List(); + if (Server.useMySQL) { + string[] rowParams; + string pri; + sql.WriteLine("CREATE TABLE IF NOT EXISTS `{0}` (", tableName); + using (DataTable schema = Database.fillData("DESCRIBE " + tableName)) { + rowParams = new string[schema.Columns.Count]; + pri = ""; + foreach (DataRow row in schema.Rows) { + //Save the info contained to file + List tmp = new List(); + for (int col = 0; col < schema.Columns.Count; col++) + tmp.Add(row.Field(col)); + + rowParams = tmp.ToArray(); + rowParams[2] = (rowParams[2].ToLower().Equals("no") ? "NOT " : "DEFAULT ") + "NULL"; + pri += (rowParams[3].ToLower().Equals("pri") ? rowParams[0] + ";" : ""); + sql.WriteLine("`{0}` {1} {2}" + (rowParams[5].Equals("") ? "" : " {5}") + (pri.Equals("") && row == schema.Rows[schema.Rows.Count - 1] ? "" : ","), rowParams); + tableSchema.Add(rowParams); + } + } + + if (pri != "") { + string[] tmp = pri.Substring(0, pri.Length - 1).Split(';'); + sql.Write("PRIMARY KEY (`"); + foreach (string prim in tmp) { + sql.Write(prim); + sql.Write("`" + (tmp[tmp.Length - 1].Equals(prim) ? ")" : ", `")); + } + } + sql.WriteLine(");"); + } else { + using (DataTable tableSQL = Database.fillData("SELECT sql FROM" + + " (SELECT * FROM sqlite_master UNION ALL" + + " SELECT * FROM sqlite_temp_master)" + + "WHERE tbl_name LIKE '" + tableName + "'" + + " AND type!='meta' AND sql NOT NULL AND name NOT LIKE 'sqlite_%'" + + "ORDER BY substr(type,2,1), name")) + { + //just print out the data in the table. + foreach (DataRow row in tableSQL.Rows) { + string tableSQLString = row.Field(0); + sql.WriteLine(tableSQLString.Replace(" " + tableName, " `" + tableName + "`").Replace("CREATE TABLE `" + tableName + "`", "CREATE TABLE IF NOT EXISTS `" + tableName + "`") + ";"); + //We parse this ourselves to find the actual types. + tableSchema = getSchema(tableSQLString); + } + } + } + sql.WriteLine(); + return tableSchema; } - private static List getSchema(string tableSQLString) - { + static List getSchema(string tableSQLString) { // All SQL for creating tables looks like "CREATE TABLE [IF NOT EXISTS] ([, ... [, PRIMARY KEY ([, ...])]]) // = [[NOT|DEFAULT] NULL] [PRIMARY KEY] [AUTO_INCREMENT] List schema = new List(); @@ -231,7 +203,7 @@ namespace MCGalaxy.SQL { //Backup using (FileStream backup = File.Create("backup.sql")) { - CopyDatabase(new StreamWriter(backup)); + BackupDatabase(new StreamWriter(backup)); } //Delete old List tables = getTables();