From 6a6133f3f7d4c7e8da53fe0b9ff832acd6a60ecc Mon Sep 17 00:00:00 2001 From: Edgar Luque Date: Sat, 9 Dec 2017 11:35:31 +0100 Subject: [PATCH 1/4] Add xml comments and DateTime datatype support for SQL --- TShockAPI/DB/IQueryBuilder.cs | 219 +++++++++++++++++++++++++++++++--- TShockAPI/DB/SqlColumn.cs | 21 +++- TShockAPI/Extensions/DbExt.cs | 9 +- 3 files changed, 233 insertions(+), 16 deletions(-) diff --git a/TShockAPI/DB/IQueryBuilder.cs b/TShockAPI/DB/IQueryBuilder.cs index 7b202aaf..614b38bc 100644 --- a/TShockAPI/DB/IQueryBuilder.cs +++ b/TShockAPI/DB/IQueryBuilder.cs @@ -19,42 +19,110 @@ along with this program. If not, see . using System; using System.Collections.Generic; using System.Linq; +using System.Runtime.Serialization; using System.Text; using MySql.Data.MySqlClient; using TShockAPI.Extensions; namespace TShockAPI.DB { + /// + /// Interface for various SQL related utilities. + /// public interface IQueryBuilder { + /// + /// Creates a table from a SqlTable object. + /// + /// The SqlTable to create the table from + /// The sql query for the table creation. string CreateTable(SqlTable table); + /// + /// 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. + /// The SQL Query string AlterTable(SqlTable from, SqlTable to); + /// + /// Converts the MySqlDbType enum to it's string representation. + /// + /// The MySqlDbType type + /// The length of the datatype + /// The string representation string DbTypeToString(MySqlDbType type, int? length); + /// + /// A UPDATE Query + /// + /// The table to update + /// The values to change + /// + /// The SQL query string UpdateValue(string table, List values, List wheres); + /// + /// A INSERT query + /// + /// The table to insert to + /// + /// The SQL Query string InsertValues(string table, List values); + /// + /// A SELECT query to get all columns + /// + /// The table to select from + /// + /// The SQL query string ReadColumn(string table, List wheres); + /// + /// Deletes row(s). + /// + /// The table to delete the row from + /// + /// The SQL query string DeleteRow(string table, List wheres); + /// + /// Renames the given table. + /// + /// Old name of the table + /// New name of the table + /// The sql query for renaming the table. string RenameTable(string from, string to); } + /// + /// Query Creator for Sqlite + /// public class SqliteQueryCreator : GenericQueryCreator, IQueryBuilder { + /// + /// Creates a table from a SqlTable object. + /// + /// The SqlTable to create the table from + /// The sql query for the table creation. public override string CreateTable(SqlTable table) { + SqlColumnErrorCheck(table.Columns); var columns = table.Columns.Select( c => - "'{0}' {1} {2} {3} {4}".SFormat(c.Name, + "'{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.NotNull ? "NOT NULL" : "", + c.DefaultCurrentTimestamp ? "DEFAULT CURRENT_TIMESTAMP" : "")); var uniques = table.Columns.Where(c => c.Unique).Select(c => c.Name); return "CREATE TABLE {0} ({1} {2})".SFormat(EscapeTableName(table.Name), string.Join(", ", columns), uniques.Count() > 0 ? ", UNIQUE({0})".SFormat(string.Join(", ", uniques)) : ""); } + /// + /// Renames the given table. + /// + /// Old name of the table + /// New name of the table + /// The sql query for renaming the table. public override string RenameTable(string from, string to) { return "ALTER TABLE {0} RENAME TO {1}".SFormat(from, to); @@ -73,8 +141,15 @@ namespace TShockAPI.DB { MySqlDbType.Int32, "INTEGER" }, { MySqlDbType.Blob, "BLOB" }, { MySqlDbType.Int64, "BIGINT"}, + { MySqlDbType.DateTime, "DATETIME"}, }; + /// + /// Converts the MySqlDbType enum to it's string representation. + /// + /// The MySqlDbType type + /// The length of the datatype + /// The string representation public string DbTypeToString(MySqlDbType type, int? length) { string ret; @@ -83,21 +158,38 @@ namespace TShockAPI.DB throw new NotImplementedException(Enum.GetName(typeof(MySqlDbType), type)); } + /// + /// Escapes the table name + /// + /// The name of the table to be escaped + /// protected override string EscapeTableName(string table) { return table.SFormat("'{0}'", table); } } + /// + /// Query Creator for MySQL + /// public class MysqlQueryCreator : GenericQueryCreator, IQueryBuilder { + /// + /// Creates a table from a SqlTable object. + /// + /// The SqlTable to create the table from + /// The sql query for the table creation. public override string CreateTable(SqlTable table) { + SqlColumnErrorCheck(table.Columns); 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 ? "AUTO_INCREMENT" : "", c.NotNull ? "NOT NULL" : "")); + "{0} {1} {2} {3} {4} {5}".SFormat(c.Name, DbTypeToString(c.Type, c.Length), + c.Primary ? "PRIMARY KEY" : "", + c.AutoIncrement ? "AUTO_INCREMENT" : "", + c.NotNull ? "NOT NULL" : "", + c.DefaultCurrentTimestamp ? "DEFAULT CURRENT_TIMESTAMP" : "")); var uniques = table.Columns.Where(c => c.Unique).Select(c => c.Name); return "CREATE TABLE {0} ({1} {2})".SFormat(EscapeTableName(table.Name), string.Join(", ", columns), uniques.Count() > 0 @@ -105,6 +197,12 @@ namespace TShockAPI.DB : ""); } + /// + /// Renames the given table. + /// + /// Old name of the table + /// New name of the table + /// The sql query for renaming the table. public override string RenameTable(string from, string to) { return "RENAME TABLE {0} TO {1}".SFormat(from, to); @@ -122,8 +220,15 @@ namespace TShockAPI.DB { MySqlDbType.Double, "DOUBLE" }, { MySqlDbType.Int32, "INT" }, { MySqlDbType.Int64, "BIGINT"}, + { MySqlDbType.DateTime, "DATETIME"}, }; + /// + /// Converts the MySqlDbType enum to it's string representation. + /// + /// The MySqlDbType type + /// The length of the datatype + /// The string representation public string DbTypeToString(MySqlDbType type, int? length) { string ret; @@ -132,17 +237,41 @@ namespace TShockAPI.DB throw new NotImplementedException(Enum.GetName(typeof(MySqlDbType), type)); } + /// + /// Escapes the table name + /// + /// The name of the table to be escaped + /// protected override string EscapeTableName(string table) { return table.SFormat("`{0}`", table); } } + /// + /// A Generic Query Creator (abstract) + /// public abstract class GenericQueryCreator { protected static Random rand = new Random(); + /// + /// Escapes the table name + /// + /// The name of the table to be escaped + /// protected abstract string EscapeTableName(string table); + /// + /// Creates a table from a SqlTable object. + /// + /// The SqlTable to create the table from + /// The sql query for the table creation. public abstract string CreateTable(SqlTable table); + /// + /// Renames the given table. + /// + /// Old name of the table + /// New name of the table + /// The sql query for renaming the table. public abstract string RenameTable(string from, string to); /// @@ -150,18 +279,9 @@ namespace TShockAPI.DB /// /// Must have name and column names. Column types are not required /// Must have column names and column types. - /// + /// The SQL Query 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)); @@ -175,11 +295,41 @@ namespace TShockAPI.DB return "{0}; {1}; {2}; {3};".SFormat(alter, create, insert, drop); } + /// + /// Check for errors in the columns. + /// + /// + /// description + public void SqlColumnErrorCheck(List columns) + { + columns.ForEach(x => + { + if(x.DefaultCurrentTimestamp && x.Type != MySqlDbType.DateTime) + { + throw new SqlColumnExcepcion("Can't set to true SqlColumn.DefaultCurrentTimestamp " + + "when the MySqlDbType is not DateTime"); + } + }); + } + + /// + /// Deletes row(s). + /// + /// The table to delete the row from + /// + /// The SQL query public string DeleteRow(string table, List wheres) { return "DELETE FROM {0} {1}".SFormat(EscapeTableName(table), BuildWhere(wheres)); } + /// + /// A UPDATE Query + /// + /// The table to update + /// The values to change + /// + /// The SQL query public string UpdateValue(string table, List values, List wheres) { if (0 == values.Count) @@ -188,11 +338,23 @@ namespace TShockAPI.DB return "UPDATE {0} SET {1} {2}".SFormat(EscapeTableName(table), string.Join(", ", values.Select(v => v.Name + " = " + v.Value)), BuildWhere(wheres)); } + /// + /// A SELECT query to get all columns + /// + /// The table to select from + /// + /// The SQL query public string ReadColumn(string table, List wheres) { return "SELECT * FROM {0} {1}".SFormat(EscapeTableName(table), BuildWhere(wheres)); } + /// + /// A INSERT query + /// + /// The table to insert to + /// + /// The SQL Query public string InsertValues(string table, List values) { var sbnames = new StringBuilder(); @@ -214,6 +376,11 @@ namespace TShockAPI.DB return "INSERT INTO {0} ({1}) VALUES ({2})".SFormat(EscapeTableName(table), sbnames, sbvalues); } + /// + /// Builds the SQL WHERE clause + /// + /// + /// protected static string BuildWhere(List wheres) { if (0 == wheres.Count) @@ -222,4 +389,28 @@ namespace TShockAPI.DB return "WHERE {0}".SFormat(string.Join(", ", wheres.Select(v => v.Name + " = " + v.Value))); } } + + /// + /// An excepcion generated by the Column check. + /// + [Serializable] + public class SqlColumnExcepcion : Exception + { + public SqlColumnExcepcion() + { + } + + public SqlColumnExcepcion(string message) + : base(message) + { + } + + public SqlColumnExcepcion(string message, Exception innerException) : base(message, innerException) + { + } + + protected SqlColumnExcepcion(SerializationInfo info, StreamingContext context) : base(info, context) + { + } + } } diff --git a/TShockAPI/DB/SqlColumn.cs b/TShockAPI/DB/SqlColumn.cs index 8a6c6bdf..cef6b3d8 100644 --- a/TShockAPI/DB/SqlColumn.cs +++ b/TShockAPI/DB/SqlColumn.cs @@ -28,11 +28,30 @@ namespace TShockAPI.DB //Optional + /// + /// Sets/Gets if it's unique + /// public bool Unique { get; set; } + /// + /// Sets/Gets if it's primary key + /// public bool Primary { get; set; } + /// + /// Sets/Gets if it autoincrements + /// public bool AutoIncrement { get; set; } + /// + /// Sets/Gets if it can be or not null + /// public bool NotNull { get; set; } + /// + /// Sets the default value + /// public string DefaultValue { get; set; } + /// + /// Use on DateTime only, if true, sets the default value to the current date when creating the row. + /// + public bool DefaultCurrentTimestamp { get; set; } /// /// Length of the data type, null = default @@ -51,4 +70,4 @@ namespace TShockAPI.DB Length = length; } } -} \ No newline at end of file +} diff --git a/TShockAPI/Extensions/DbExt.cs b/TShockAPI/Extensions/DbExt.cs index 3db75ec6..b623cae1 100644 --- a/TShockAPI/Extensions/DbExt.cs +++ b/TShockAPI/Extensions/DbExt.cs @@ -23,6 +23,9 @@ using System.Diagnostics.CodeAnalysis; namespace TShockAPI.DB { + /// + /// Database extensions + /// public static class DbExt { /// @@ -189,6 +192,10 @@ namespace TShockAPI.DB typeof (double?), (s, i) => s.IsDBNull(i) ? null : (object)s.GetDouble(i) }, + { + typeof (DateTime), + (s, i) => s.IsDBNull(i) ? null : (object)s.GetDateTime(i) + }, { typeof (object), (s, i) => s.GetValue(i) @@ -272,4 +279,4 @@ namespace TShockAPI.DB return Reader.Get(Reader.GetOrdinal(column)); } } -} \ No newline at end of file +} From 83f02e49aa662871e0bb812218e5280f0aeca35f Mon Sep 17 00:00:00 2001 From: Edgar Luque Date: Sat, 9 Dec 2017 16:04:27 +0100 Subject: [PATCH 2/4] Format better --- TShockAPI/Extensions/DbExt.cs | 162 +++++++++++++++++----------------- 1 file changed, 81 insertions(+), 81 deletions(-) diff --git a/TShockAPI/Extensions/DbExt.cs b/TShockAPI/Extensions/DbExt.cs index b623cae1..fbed21f7 100644 --- a/TShockAPI/Extensions/DbExt.cs +++ b/TShockAPI/Extensions/DbExt.cs @@ -106,7 +106,7 @@ namespace TShockAPI.DB public static IDbConnection CloneEx(this IDbConnection conn) { - var clone = (IDbConnection) Activator.CreateInstance(conn.GetType()); + var clone = (IDbConnection)Activator.CreateInstance(conn.GetType()); clone.ConnectionString = conn.ConnectionString; return clone; } @@ -123,84 +123,84 @@ namespace TShockAPI.DB private static readonly Dictionary> ReadFuncs = new Dictionary > - { - { - typeof (bool), - (s, i) => s.GetBoolean(i) - }, - { - typeof (bool?), - (s, i) => s.IsDBNull(i) ? null : (object)s.GetBoolean(i) - }, - { - typeof (byte), - (s, i) => s.GetByte(i) - }, - { - typeof (byte?), - (s, i) => s.IsDBNull(i) ? null : (object)s.GetByte(i) - }, - { - typeof (Int16), - (s, i) => s.GetInt16(i) - }, - { - typeof (Int16?), - (s, i) => s.IsDBNull(i) ? null : (object)s.GetInt16(i) - }, - { - typeof (Int32), - (s, i) => s.GetInt32(i) - }, - { - typeof (Int32?), - (s, i) => s.IsDBNull(i) ? null : (object)s.GetInt32(i) - }, - { - typeof (Int64), - (s, i) => s.GetInt64(i) - }, - { - typeof (Int64?), - (s, i) => s.IsDBNull(i) ? null : (object)s.GetInt64(i) - }, - { - typeof (string), - (s, i) => s.GetString(i) - }, - { - typeof (decimal), - (s, i) => s.GetDecimal(i) - }, - { - typeof (decimal?), - (s, i) => s.IsDBNull(i) ? null : (object)s.GetDecimal(i) - }, - { - typeof (float), - (s, i) => s.GetFloat(i) - }, - { - typeof (float?), - (s, i) => s.IsDBNull(i) ? null : (object)s.GetFloat(i) - }, - { - typeof (double), - (s, i) => s.GetDouble(i) - }, - { - typeof (double?), - (s, i) => s.IsDBNull(i) ? null : (object)s.GetDouble(i) - }, - { - typeof (DateTime), - (s, i) => s.IsDBNull(i) ? null : (object)s.GetDateTime(i) - }, - { - typeof (object), - (s, i) => s.GetValue(i) - }, - }; + { + { + typeof (bool), + (s, i) => s.GetBoolean(i) + }, + { + typeof (bool?), + (s, i) => s.IsDBNull(i) ? null : (object)s.GetBoolean(i) + }, + { + typeof (byte), + (s, i) => s.GetByte(i) + }, + { + typeof (byte?), + (s, i) => s.IsDBNull(i) ? null : (object)s.GetByte(i) + }, + { + typeof (Int16), + (s, i) => s.GetInt16(i) + }, + { + typeof (Int16?), + (s, i) => s.IsDBNull(i) ? null : (object)s.GetInt16(i) + }, + { + typeof (Int32), + (s, i) => s.GetInt32(i) + }, + { + typeof (Int32?), + (s, i) => s.IsDBNull(i) ? null : (object)s.GetInt32(i) + }, + { + typeof (Int64), + (s, i) => s.GetInt64(i) + }, + { + typeof (Int64?), + (s, i) => s.IsDBNull(i) ? null : (object)s.GetInt64(i) + }, + { + typeof (string), + (s, i) => s.GetString(i) + }, + { + typeof (decimal), + (s, i) => s.GetDecimal(i) + }, + { + typeof (decimal?), + (s, i) => s.IsDBNull(i) ? null : (object)s.GetDecimal(i) + }, + { + typeof (float), + (s, i) => s.GetFloat(i) + }, + { + typeof (float?), + (s, i) => s.IsDBNull(i) ? null : (object)s.GetFloat(i) + }, + { + typeof (double), + (s, i) => s.GetDouble(i) + }, + { + typeof (double?), + (s, i) => s.IsDBNull(i) ? null : (object)s.GetDouble(i) + }, + { + typeof (DateTime), + (s, i) => s.IsDBNull(i) ? null : (object)s.GetDateTime(i) + }, + { + typeof (object), + (s, i) => s.GetValue(i) + }, + }; public static T Get(this IDataReader reader, string column) { @@ -212,8 +212,8 @@ namespace TShockAPI.DB if (reader.IsDBNull(column)) return default(T); - if (ReadFuncs.ContainsKey(typeof (T))) - return (T) ReadFuncs[typeof (T)](reader, column); + if (ReadFuncs.ContainsKey(typeof(T))) + return (T)ReadFuncs[typeof(T)](reader, column); throw new NotImplementedException(); } From 4575792987f031a36f7849aac7ea84154cebef95 Mon Sep 17 00:00:00 2001 From: Edgar Luque Date: Sat, 9 Dec 2017 16:45:31 +0100 Subject: [PATCH 3/4] Formatted a bit better and moved SqlColumnException to SqlColumn.cs --- TShockAPI/DB/IQueryBuilder.cs | 60 ++++++++++++++--------------------- TShockAPI/DB/SqlColumn.cs | 16 ++++++++++ 2 files changed, 39 insertions(+), 37 deletions(-) diff --git a/TShockAPI/DB/IQueryBuilder.cs b/TShockAPI/DB/IQueryBuilder.cs index 614b38bc..917f634d 100644 --- a/TShockAPI/DB/IQueryBuilder.cs +++ b/TShockAPI/DB/IQueryBuilder.cs @@ -16,12 +16,12 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . */ +using MySql.Data.MySqlClient; using System; using System.Collections.Generic; using System.Linq; using System.Runtime.Serialization; using System.Text; -using MySql.Data.MySqlClient; using TShockAPI.Extensions; namespace TShockAPI.DB @@ -37,6 +37,7 @@ namespace TShockAPI.DB /// The SqlTable to create the table from /// The sql query for the table creation. string CreateTable(SqlTable table); + /// /// Alter a table from source to destination /// @@ -44,6 +45,7 @@ namespace TShockAPI.DB /// Must have column names and column types. /// The SQL Query string AlterTable(SqlTable from, SqlTable to); + /// /// Converts the MySqlDbType enum to it's string representation. /// @@ -51,6 +53,7 @@ namespace TShockAPI.DB /// The length of the datatype /// The string representation string DbTypeToString(MySqlDbType type, int? length); + /// /// A UPDATE Query /// @@ -59,6 +62,7 @@ namespace TShockAPI.DB /// /// The SQL query string UpdateValue(string table, List values, List wheres); + /// /// A INSERT query /// @@ -66,6 +70,7 @@ namespace TShockAPI.DB /// /// The SQL Query string InsertValues(string table, List values); + /// /// A SELECT query to get all columns /// @@ -73,6 +78,7 @@ namespace TShockAPI.DB /// /// The SQL query string ReadColumn(string table, List wheres); + /// /// Deletes row(s). /// @@ -80,6 +86,7 @@ namespace TShockAPI.DB /// /// The SQL query string DeleteRow(string table, List wheres); + /// /// Renames the given table. /// @@ -101,18 +108,18 @@ namespace TShockAPI.DB /// The sql query for the table creation. public override string CreateTable(SqlTable table) { - SqlColumnErrorCheck(table.Columns); + ValidateSqlColumnType(table.Columns); var columns = table.Columns.Select( c => - "'{0}' {1} {2} {3} {4} {5}".SFormat(c.Name, - DbTypeToString(c.Type, c.Length), + "'{0}' {1} {2} {3} {4} {5}".SFormat(c.Name, + DbTypeToString(c.Type, c.Length), c.Primary ? "PRIMARY KEY" : "", - c.AutoIncrement ? "AUTOINCREMENT" : "", + c.AutoIncrement ? "AUTOINCREMENT" : "", c.NotNull ? "NOT NULL" : "", c.DefaultCurrentTimestamp ? "DEFAULT CURRENT_TIMESTAMP" : "")); var uniques = table.Columns.Where(c => c.Unique).Select(c => c.Name); - return "CREATE TABLE {0} ({1} {2})".SFormat(EscapeTableName(table.Name), + return "CREATE TABLE {0} ({1} {2})".SFormat(EscapeTableName(table.Name), string.Join(", ", columns), uniques.Count() > 0 ? ", UNIQUE({0})".SFormat(string.Join(", ", uniques)) : ""); } @@ -140,7 +147,7 @@ namespace TShockAPI.DB { MySqlDbType.Double, "REAL" }, { MySqlDbType.Int32, "INTEGER" }, { MySqlDbType.Blob, "BLOB" }, - { MySqlDbType.Int64, "BIGINT"}, + { MySqlDbType.Int64, "BIGINT"}, { MySqlDbType.DateTime, "DATETIME"}, }; @@ -181,7 +188,7 @@ namespace TShockAPI.DB /// The sql query for the table creation. public override string CreateTable(SqlTable table) { - SqlColumnErrorCheck(table.Columns); + ValidateSqlColumnType(table.Columns); var columns = table.Columns.Select( c => @@ -219,7 +226,7 @@ namespace TShockAPI.DB { MySqlDbType.Float, "FLOAT" }, { MySqlDbType.Double, "DOUBLE" }, { MySqlDbType.Int32, "INT" }, - { MySqlDbType.Int64, "BIGINT"}, + { MySqlDbType.Int64, "BIGINT"}, { MySqlDbType.DateTime, "DATETIME"}, }; @@ -254,18 +261,21 @@ namespace TShockAPI.DB public abstract class GenericQueryCreator { protected static Random rand = new Random(); + /// /// Escapes the table name /// /// The name of the table to be escaped /// protected abstract string EscapeTableName(string table); + /// /// Creates a table from a SqlTable object. /// /// The SqlTable to create the table from /// The sql query for the table creation. public abstract string CreateTable(SqlTable table); + /// /// Renames the given table. /// @@ -299,14 +309,14 @@ namespace TShockAPI.DB /// Check for errors in the columns. /// /// - /// description - public void SqlColumnErrorCheck(List columns) + /// + public void ValidateSqlColumnType(List columns) { columns.ForEach(x => { - if(x.DefaultCurrentTimestamp && x.Type != MySqlDbType.DateTime) + if (x.DefaultCurrentTimestamp && x.Type != MySqlDbType.DateTime) { - throw new SqlColumnExcepcion("Can't set to true SqlColumn.DefaultCurrentTimestamp " + + throw new SqlColumnException("Can't set to true SqlColumn.DefaultCurrentTimestamp " + "when the MySqlDbType is not DateTime"); } }); @@ -389,28 +399,4 @@ namespace TShockAPI.DB return "WHERE {0}".SFormat(string.Join(", ", wheres.Select(v => v.Name + " = " + v.Value))); } } - - /// - /// An excepcion generated by the Column check. - /// - [Serializable] - public class SqlColumnExcepcion : Exception - { - public SqlColumnExcepcion() - { - } - - public SqlColumnExcepcion(string message) - : base(message) - { - } - - public SqlColumnExcepcion(string message, Exception innerException) : base(message, innerException) - { - } - - protected SqlColumnExcepcion(SerializationInfo info, StreamingContext context) : base(info, context) - { - } - } } diff --git a/TShockAPI/DB/SqlColumn.cs b/TShockAPI/DB/SqlColumn.cs index cef6b3d8..d61501d6 100644 --- a/TShockAPI/DB/SqlColumn.cs +++ b/TShockAPI/DB/SqlColumn.cs @@ -17,6 +17,7 @@ along with this program. If not, see . */ using MySql.Data.MySqlClient; +using System; namespace TShockAPI.DB { @@ -70,4 +71,19 @@ namespace TShockAPI.DB Length = length; } } + + /// + /// Used when a SqlColumn has validation errors. + /// + [Serializable] + public class SqlColumnException : Exception + { + /// + /// Creates a new SqlColumnException with the given message. + /// + /// + public SqlColumnException(string message) : base(message) + { + } + } } From 7d98e3db774700e4bc853bbf65cbaf48c1b51214 Mon Sep 17 00:00:00 2001 From: Ryozuki Date: Sun, 10 Dec 2017 09:39:20 +0100 Subject: [PATCH 4/4] update changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index f1a85365..346f73dc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -26,6 +26,7 @@ This is the rolling changelog for TShock for Terraria. Use past tense when addin * Update OTAPI to 2.0.0.31, which also updates Newtonsoft.Json to 10.0.3 (@Ryozuki) * Fixed DumpItems() from trying to dump older versions of certain items (negative item IDs). (@Zaicon) * Added the `/dump-reference-data` command, which when run, runs Utils.Dump() and outputs Terraria reference data to the server folder. (@hakusaro) +* Added DateTime datatype support for both MySQL and SQLite. (@Ryozuki) ## TShock 4.3.24 * Updated OpenTerraria API to 1.3.5.3 (@DeathCradle)