diff --git a/TShockAPI/DB/IQueryBuilder.cs b/TShockAPI/DB/IQueryBuilder.cs index 9157e645..3037b58b 100644 --- a/TShockAPI/DB/IQueryBuilder.cs +++ b/TShockAPI/DB/IQueryBuilder.cs @@ -33,11 +33,12 @@ namespace TShockAPI.DB string InsertValues(string table, List values); string ReadColumn(string table, List wheres); string DeleteRow(string table, List wheres); + string RenameTable(string from, string to); } - public class SqliteQueryCreator : IQueryBuilder + public class SqliteQueryCreator : GenericQueryCreator, IQueryBuilder { - public string CreateTable(SqlTable table) + public override string CreateTable(SqlTable table) { var columns = table.Columns.Select( @@ -45,129 +46,12 @@ namespace TShockAPI.DB "'{0}' {1} {2} {3} {4} {5}".SFormat(c.Name, DbTypeToString(c.Type, c.Length), c.Primary ? "PRIMARY KEY" : "", c.AutoIncrement ? "AUTOINCREMENT" : "", c.NotNull ? "NOT NULL" : "", c.Unique ? "UNIQUE" : "")); - return "CREATE TABLE '{0}' ({1})".SFormat(table.Name, string.Join(", ", columns)); + return "CREATE TABLE {0} ({1})".SFormat(EscapeTableName(table.Name), string.Join(", ", columns)); } - private static Random rand = new Random(); - - /// - /// Alter a table from source to destination - /// - /// Must have name and column names. Column types are not required - /// Must have column names and column types. - /// - public string AlterTable(SqlTable from, SqlTable to) + public override string RenameTable(string from, string to) { - var rstr = rand.NextString(20); - var alter = "ALTER TABLE '{0}' RENAME TO '{1}_{0}'".SFormat(from.Name, rstr); - var create = CreateTable(to); - //combine all columns in the 'from' variable excluding ones that aren't in the 'to' variable. - //exclude the ones that aren't in 'to' variable because if the column is deleted, why try to import the data? - var insert = "INSERT INTO '{0}' ({1}) SELECT {1} FROM {2}_{0}".SFormat(from.Name, - string.Join(", ", - from.Columns.Where( - c => - to.Columns.Any( - c2 => c2.Name == c.Name)).Select - (c => c.Name)), rstr); - var drop = "DROP TABLE '{0}_{1}'".SFormat(rstr, from.Name); - return "{0}; {1}; {2}; {3};".SFormat(alter, create, insert, drop); - /* - ALTER TABLE "main"."Bans" RENAME TO "oXHFcGcd04oXHFcGcd04_Bans" - CREATE TABLE "main"."Bans" ("IP" TEXT PRIMARY KEY ,"Name" TEXT) - INSERT INTO "main"."Bans" SELECT "IP","Name" FROM "main"."oXHFcGcd04oXHFcGcd04_Bans" - DROP TABLE "main"."oXHFcGcd04oXHFcGcd04_Bans" - * - * Twitchy - Oh. I get it! - */ - } - - public string DeleteRow(string table, List wheres) - { - var sbwheres = new StringBuilder(); - int count = 0; - foreach (SqlValue where in wheres) - { - sbwheres.Append(where.Name + "=" + where.Value); - if (count != wheres.Count - 1) - sbwheres.Append(" AND "); - count++; - } - if (wheres.Count > 0) - return "DELETE FROM '{0}' WHERE {1} ".SFormat(table, sbwheres.ToString()); - else - return "DELETE FROM '{0}'".SFormat(table, sbwheres.ToString()); - } - - public string UpdateValue(string table, List values, List wheres) - { - var sbvalues = new StringBuilder(); - var sbwheres = new StringBuilder(); - int count = 0; - foreach (SqlValue value in values) - { - sbvalues.Append(value.Name + "=" + value.Value); - if (count != values.Count - 1) - sbvalues.Append(","); - count++; - } - count = 0; - foreach (SqlValue where in wheres) - { - sbwheres.Append(where.Name + "=" + where.Value); - if (count != wheres.Count - 1) - sbwheres.Append(" AND "); - count++; - } - - if (wheres.Count > 0) - return "UPDATE '{0}' SET {1} WHERE {2}".SFormat(table, sbvalues.ToString(), sbwheres.ToString()); - else - return "UPDATE '{0}' SET {1}".SFormat(table, sbvalues.ToString()); - } - - public string InsertValues(string table, List values) - { - var sbnames = new StringBuilder(); - var sbvalues = new StringBuilder(); - int count = 0; - - foreach (SqlValue name in values) - { - sbnames.Append(name.Name); - - if (count != values.Count - 1) - sbnames.Append(", "); - count++; - } - count = 0; - foreach (SqlValue value in values) - { - sbvalues.Append(value.Value.ToString()); - if (count != values.Count - 1) - sbvalues.Append(", "); - count++; - } - return "INSERT INTO '{0}' ({1}) VALUES ({2})".SFormat(table, sbnames.ToString(), sbvalues.ToString()); - } - - public string ReadColumn(string table, List wheres) - { - var sbwheres = new StringBuilder(); - int count = 0; - - foreach (SqlValue where in wheres) - { - sbwheres.Append(where.Name + "=" + where.Value); - if (count != wheres.Count - 1) - sbwheres.Append(" AND "); - count++; - } - - if (wheres.Count > 0) - return "SELECT * FROM {0} WHERE {1}".SFormat(table, sbwheres.ToString()); - else - return "SELECT * FROM {0}".SFormat(table); + return "ALTER TABLE {0} RENAME TO {1}".SFormat(from, to); } private static readonly Dictionary TypesAsStrings = new Dictionary @@ -189,11 +73,16 @@ namespace TShockAPI.DB return ret; throw new NotImplementedException(Enum.GetName(typeof (MySqlDbType), type)); } + + protected override string EscapeTableName(string table) + { + return table.SFormat("'{0}'", table); + } } - public class MysqlQueryCreator : IQueryBuilder + public class MysqlQueryCreator : GenericQueryCreator, IQueryBuilder { - public string CreateTable(SqlTable table) + public override string CreateTable(SqlTable table) { var columns = table.Columns.Select( @@ -201,125 +90,15 @@ namespace TShockAPI.DB "{0} {1} {2} {3} {4}".SFormat(c.Name, DbTypeToString(c.Type, c.Length), c.Primary ? "PRIMARY KEY" : "", c.AutoIncrement ? "AUTO_INCREMENT" : "", c.NotNull ? "NOT NULL" : "")); var uniques = table.Columns.Where(c => c.Unique).Select(c => c.Name); - return "CREATE TABLE {0} ({1} {2})".SFormat(table.Name, string.Join(", ", columns), + return "CREATE TABLE {0} ({1} {2})".SFormat(EscapeTableName(table.Name), string.Join(", ", columns), uniques.Count() > 0 ? ", UNIQUE({0})".SFormat(string.Join(", ", uniques)) : ""); } - private static Random rand = new Random(); - - /// - /// Alter a table from source to destination - /// - /// Must have name and column names. Column types are not required - /// Must have column names and column types. - /// - public string AlterTable(SqlTable from, SqlTable to) + public override string RenameTable(string from, string to) { - var rstr = rand.NextString(20); - var alter = "RENAME TABLE {0} TO {1}_{0}".SFormat(from.Name, rstr); - var create = CreateTable(to); - //combine all columns in the 'from' variable excluding ones that aren't in the 'to' variable. - //exclude the ones that aren't in 'to' variable because if the column is deleted, why try to import the data? - var insert = "INSERT INTO {0} ({1}) SELECT {1} FROM {2}_{0}".SFormat(from.Name, - string.Join(", ", - from.Columns.Where( - c => - to.Columns.Any( - c2 => c2.Name == c.Name)).Select( - c => c.Name)), rstr); - var drop = "DROP TABLE {0}_{1}".SFormat(rstr, from.Name); - return "{0}; {1}; {2}; {3};".SFormat(alter, create, insert, drop); - } - - public string DeleteRow(string table, List wheres) - { - var sbwheres = new StringBuilder(); - int count = 0; - foreach (SqlValue where in wheres) - { - sbwheres.Append(where.Name + "=" + where.Value); - if (count != wheres.Count - 1) - sbwheres.Append(" AND "); - count++; - } - if (wheres.Count > 0) - return "DELETE FROM {0} WHERE {1} ".SFormat(table, sbwheres.ToString()); - else - return "DELETE FROM {0}".SFormat(table, sbwheres.ToString()); - } - - public string UpdateValue(string table, List values, List wheres) - { - var sbvalues = new StringBuilder(); - var sbwheres = new StringBuilder(); - int count = 0; - foreach (SqlValue value in values) - { - sbvalues.Append(value.Name + "=" + value.Value); - if (count != values.Count - 1) - sbvalues.Append("AND"); - count++; - } - count = 0; - foreach (SqlValue where in wheres) - { - sbwheres.Append(where.Name + "=" + where.Value); - if (count != wheres.Count - 1) - sbwheres.Append(" AND "); - count++; - } - - if (wheres.Count > 0) - return "UPDATE {0} SET {1} WHERE {2}".SFormat(table, sbvalues.ToString(), sbwheres.ToString()); - else - return "UPDATE {0} SET {1}".SFormat(table, sbvalues.ToString()); - } - - public string InsertValues(string table, List values) - { - var sbnames = new StringBuilder(); - var sbvalues = new StringBuilder(); - int count = 0; - - foreach (SqlValue name in values) - { - sbnames.Append(name.Name); - - if (count != values.Count - 1) - sbnames.Append(", "); - count++; - } - count = 0; - foreach (SqlValue value in values) - { - sbvalues.Append(value.Value.ToString()); - if (count != values.Count - 1) - sbvalues.Append(", "); - count++; - } - - return "INSERT INTO {0} ({1}) VALUES ({2})".SFormat(table, sbnames.ToString(), sbvalues.ToString()); - } - - public string ReadColumn(string table, List wheres) - { - var sbwheres = new StringBuilder(); - int count = 0; - - foreach (SqlValue where in wheres) - { - sbwheres.Append(where.Name + "=" + where.Value); - if (count != wheres.Count - 1) - sbwheres.Append(" AND "); - count++; - } - - if (wheres.Count > 0) - return "SELECT * FROM {0} WHERE {1}".SFormat(table, sbwheres.ToString()); - else - return "SELECT * FROM {0}".SFormat(table); + return "RENAME TABLE {0} TO {1}".SFormat(from, to); } private static readonly Dictionary TypesAsStrings = new Dictionary @@ -340,5 +119,95 @@ namespace TShockAPI.DB return ret + (length != null ? "({0})".SFormat((int) length) : ""); throw new NotImplementedException(Enum.GetName(typeof (MySqlDbType), type)); } + + protected override string EscapeTableName(string table) + { + return table.SFormat("`{0}`", table); + } } -} \ No newline at end of file + + public abstract class GenericQueryCreator + { + protected static Random rand = new Random(); + protected abstract string EscapeTableName(string table); + public abstract string CreateTable(SqlTable table); + public abstract string RenameTable(string from, string to); + + /// + /// Alter a table from source to destination + /// + /// Must have name and column names. Column types are not required + /// Must have column names and column types. + /// + public string AlterTable(SqlTable from, SqlTable to) + { + /* + * Any example outpuf from this looks like:- + ALTER TABLE "main"."Bans" RENAME TO "oXHFcGcd04oXHFcGcd04_Bans" + CREATE TABLE "main"."Bans" ("IP" TEXT PRIMARY KEY ,"Name" TEXT) + INSERT INTO "main"."Bans" SELECT "IP","Name" FROM "main"."oXHFcGcd04oXHFcGcd04_Bans" + DROP TABLE "main"."oXHFcGcd04oXHFcGcd04_Bans" + * + * Twitchy - Oh. I get it! + */ + var rstr = rand.NextString(20); + var escapedTable = EscapeTableName(from.Name); + var tmpTable = EscapeTableName("{0}_{1}".SFormat(rstr, from.Name)); + var alter = RenameTable(escapedTable, tmpTable); + var create = CreateTable(to); + // combine all columns in the 'from' variable excluding ones that aren't in the 'to' variable. + // exclude the ones that aren't in 'to' variable because if the column is deleted, why try to import the data? + var columns = string.Join(", ", from.Columns.Where(c => to.Columns.Any(c2 => c2.Name == c.Name)).Select(c => c.Name)); + var insert = "INSERT INTO {0} ({1}) SELECT {1} FROM {2}".SFormat(escapedTable, columns, tmpTable); + var drop = "DROP TABLE {0}".SFormat(tmpTable); + return "{0}; {1}; {2}; {3};".SFormat(alter, create, insert, drop); + } + + public string DeleteRow(string table, List wheres) + { + return "DELETE FROM {0}{1}".SFormat(EscapeTableName(table), BuildWhere(wheres)); + } + + public string UpdateValue(string table, List values, List wheres) + { + if (0 == values.Count) + throw new ArgumentException("No values supplied"); + + return "UPDATE {0} SET {1}{2}".SFormat(EscapeTableName(table), string.Join(", ", values.Select(v => v.Name + " = " + v.Value)), BuildWhere(wheres)); + } + + public string ReadColumn(string table, List wheres) + { + return "SELECT * FROM {0}{1}".SFormat(EscapeTableName(table), BuildWhere(wheres)); + } + + public string InsertValues(string table, List values) + { + var sbnames = new StringBuilder(); + var sbvalues = new StringBuilder(); + int count = 0; + foreach (SqlValue value in values) + { + sbnames.Append(value.Name); + sbvalues.Append(value.Value.ToString()); + + if (count != values.Count - 1) + { + sbnames.Append(", "); + sbvalues.Append(", "); + } + count++; + } + + return "INSERT INTO {0} ({1}) VALUES ({2})".SFormat(EscapeTableName(table), sbnames, sbvalues); + } + + protected static string BuildWhere(List wheres) + { + if (0 == wheres.Count) + return string.Empty; + + return "WHERE {2}".SFormat(string.Join(", ", wheres.Select(v => v.Name + " = " + v.Value))); + } + } +}