diff --git a/TShockAPI/DB/GroupManager.cs b/TShockAPI/DB/GroupManager.cs
index 4fec6cb8..93b093f4 100644
--- a/TShockAPI/DB/GroupManager.cs
+++ b/TShockAPI/DB/GroupManager.cs
@@ -3,6 +3,7 @@ using System.Collections.Generic;
using System.Data;
using System.IO;
using System.Linq;
+using MySql.Data.MySqlClient;
namespace TShockAPI.DB
{
@@ -18,13 +19,13 @@ namespace TShockAPI.DB
string query = "";
- var table = new SqlTable("GroupList",
- new SqlColumn("GroupName", "TEXT") { Primary = true },
- new SqlColumn("Commands", "TEXT"),
- new SqlColumn("ChatColor", "TEXT")
+ /*var table = new SqlTable("GroupList",
+ new SqlColumn("GroupName", MySqlDbType.VarChar, 32) { Primary = true },
+ new SqlColumn("Commands", MySqlDbType.Text),
+ new SqlColumn("ChatColor", MySqlDbType.Text)
);
- //new SqlTableCreator(db).EnsureExists(table);
+ new SqlTableCreator(db, new MysqlQueryCreator()).EnsureExists(table);*/
if (db.GetSqlType() == SqlType.Sqlite)
diff --git a/TShockAPI/DB/IQueryBuilder.cs b/TShockAPI/DB/IQueryBuilder.cs
index fa7c28d2..903a18a4 100644
--- a/TShockAPI/DB/IQueryBuilder.cs
+++ b/TShockAPI/DB/IQueryBuilder.cs
@@ -1,7 +1,9 @@
using System;
using System.Collections.Generic;
+using System.Data;
using System.Linq;
using System.Text;
+using MySql.Data.MySqlClient;
using TShockAPI.Extensions;
namespace TShockAPI.DB
@@ -10,19 +12,33 @@ namespace TShockAPI.DB
{
string CreateTable(SqlTable table);
string AlterTable(SqlTable from, SqlTable to);
+ string DbTypeToString(MySqlDbType type, int? length);
}
public class SqliteQueryCreator : IQueryBuilder
{
public string CreateTable(SqlTable table)
{
- var columns = table.Columns.Select(c => "'{0}' {1} {2} {3} {4}".SFormat(c.Name, c.Type, c.Primary ? "PRIMARY KEY" : "", c.AutoIncrement ? "AUTOINCREMENT" : "", c.NotNull ? "NOT NULL" : "", c.Unique ? "UNIQUE" : ""));
+ var columns = table.Columns.Select(c => "'{0}' {1} {2} {3} {4}".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));
}
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)
{
- return "";
+ 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)
@@ -30,18 +46,68 @@ namespace TShockAPI.DB
DROP TABLE "main"."oXHFcGcd04oXHFcGcd04_Bans"
*/
}
+
+
+ static readonly Dictionary TypesAsStrings = new Dictionary
+ {
+ {MySqlDbType.VarChar, "TEXT"},
+ {MySqlDbType.String, "TEXT"},
+ {MySqlDbType.Text, "TEXT"},
+ {MySqlDbType.TinyText, "TEXT"},
+ {MySqlDbType.MediumText, "TEXT"},
+ {MySqlDbType.LongText, "TEXT"},
+ };
+ public string DbTypeToString(MySqlDbType type, int? length)
+ {
+ string ret;
+ if (TypesAsStrings.TryGetValue(type, out ret))
+ return ret;
+ throw new NotImplementedException(Enum.GetName(typeof(MySqlDbType), type));
+ }
}
public class MysqlQueryCreator : IQueryBuilder
{
public string CreateTable(SqlTable table)
{
- throw new NotImplementedException();
+ var columns = table.Columns.Select(c => "{0} {1} {2} {3}".SFormat(c.Name, DbTypeToString(c.Type, c.Length), c.Primary ? "PRIMARY KEY" : "", c.AutoIncrement ? "AUTOINCREMENT" : "", 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), uniques.Count() > 0 ? ", UNIQUE({0})".SFormat(string.Join(", ", uniques)) : "");
+ }
+ 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)
+ {
+ 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 AlterTable(SqlTable from, SqlTable to)
+ static readonly Dictionary TypesAsStrings = new Dictionary
+ {
+ {MySqlDbType.VarChar, "VARCHAR"},
+ {MySqlDbType.String, "CHAR"},
+ {MySqlDbType.Text, "TEXT"},
+ {MySqlDbType.TinyText, "TINYTEXT"},
+ {MySqlDbType.MediumText, "MEDIUMTEXT"},
+ {MySqlDbType.LongText, "LONGTEXT"},
+ };
+ public string DbTypeToString(MySqlDbType type, int? length)
{
- throw new NotImplementedException();
+ string ret;
+ if (TypesAsStrings.TryGetValue(type, out ret))
+ return ret + (length != null ? "({0})".SFormat((int)length) : "");
+ throw new NotImplementedException(Enum.GetName(typeof(MySqlDbType), type));
}
}
}
diff --git a/TShockAPI/DB/SqlColumn.cs b/TShockAPI/DB/SqlColumn.cs
index ff8472a2..8e86498c 100644
--- a/TShockAPI/DB/SqlColumn.cs
+++ b/TShockAPI/DB/SqlColumn.cs
@@ -1,7 +1,4 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
+using MySql.Data.MySqlClient;
namespace TShockAPI.DB
{
@@ -9,7 +6,8 @@ namespace TShockAPI.DB
{
//Required
public string Name { get; set; }
- public string Type { get; set; }
+ public MySqlDbType Type { get; set; }
+
//Optional
public bool Unique { get; set; }
@@ -18,10 +16,20 @@ namespace TShockAPI.DB
public bool NotNull { get; set; }
public string DefaultValue { get; set; }
- public SqlColumn(string name, string type)
+ ///
+ /// Length of the data type, null = default
+ ///
+ public int? Length { get; set; }
+
+ public SqlColumn(string name, MySqlDbType type)
+ : this(name, type, null)
+ {
+ }
+ public SqlColumn(string name, MySqlDbType type, int? length)
{
Name = name;
Type = type;
+ Length = length;
}
}
}
diff --git a/TShockAPI/DB/SqlTable.cs b/TShockAPI/DB/SqlTable.cs
index e2910c9d..3ccca4c4 100644
--- a/TShockAPI/DB/SqlTable.cs
+++ b/TShockAPI/DB/SqlTable.cs
@@ -3,6 +3,7 @@ using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Text;
+using MySql.Data.MySqlClient;
namespace TShockAPI.DB
{
@@ -36,9 +37,10 @@ namespace TShockAPI.DB
var columns = GetColumns(table);
if (columns.Count > 0)
{
- if (table.Columns.All(c => columns.Contains(c.Name)))
+ if (!table.Columns.All(c => columns.Contains(c.Name)) || !columns.All(c => table.Columns.Any(c2 => c2.Name == c)))
{
-
+ var from = new SqlTable(table.Name, columns.Select(s => new SqlColumn(s, MySqlDbType.String)).ToList());
+ database.Query(creator.AlterTable(from, table));
}
}
else
@@ -61,7 +63,11 @@ namespace TShockAPI.DB
}
else if (name == SqlType.Mysql)
{
- throw new NotImplementedException();
+ using (var reader = database.QueryReader("SELECT COLUMN_NAME FROM information_schema.COLUMNS WHERE TABLE_NAME=@0 AND TABLE_SCHEMA=@1", table.Name, database.Database))
+ {
+ while (reader.Read())
+ ret.Add(reader.Get("COLUMN_NAME"));
+ }
}
else
{
diff --git a/TShockAPI/Extensions/DbExt.cs b/TShockAPI/Extensions/DbExt.cs
index d6541c0c..25429577 100644
--- a/TShockAPI/Extensions/DbExt.cs
+++ b/TShockAPI/Extensions/DbExt.cs
@@ -71,7 +71,7 @@ namespace TShockAPI.DB
var name = conn.GetType().Name;
if (name == "SqliteConnection")
return SqlType.Sqlite;
- if (name == "MysqlConnection")
+ if (name == "MySqlConnection")
return SqlType.Mysql;
return SqlType.Unknown;
}